Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Serverless and Web API best practices on Google Cloud

Serverless and Web API best practices on Google Cloud

The goal of this workshop is to gain experience with "serverless" services offered by Google Cloud Platform:

Cloud Functions — to deploy small units of business logic in the shape of functions, that react to various events (Pub/Sub messages, new files in Cloud Storage, HTTP requests, and more),
App Engine — to deploy and serve web apps, web APIs, mobile backends, static assets, with fast scale up and down capabilities,
Cloud Run — to deploy and scale containers, that can contain any language, runtime or library.

And to discover how to take advantage of those serverless services to deploy and scale Web and REST APIs, while also seeing some good RESTful design principles along the way.

In this workshop, we'll create a bookshelf explorer consisting of:

A Cloud Function: to import the initial dataset of books available in our library, in the Cloud Firestore document database,
A Cloud Run container: that will expose a REST API over the content of our database,
An App Engine web frontend: to browse through the list of books, by calling our REST API.

Guillaume Laforge

April 14, 2021
Tweet

More Decks by Guillaume Laforge

Other Decks in Technology

Transcript

  1. Proprietary + Confidential
    Serverless and
    Web API workshop
    on Google Cloud
    Guillaume Laforge — @glaforge
    Developer Advocate, Google Cloud
    April 2021

    View full-size slide

  2. Proprietary + Confidential
    Agenda
    In this workshop, we’ll introduce the definition of
    “Serverless” and discover the serverless
    compute options available on Google Cloud
    Platform.
    Then, we’ll move on to discuss best practices in
    the design of Web APIs, and how you can take
    advantage of serverless products.
    Finally, we’ll put everything in action, through
    hands-on codelabs.
    Introduction to Serverless
    on Google Cloud
    1
    Web API best practices
    2
    Hands-on codelabs
    3
    Q&A
    4
    Conclusion
    5

    View full-size slide

  3. Proprietary + Confidential
    Serverless spectrum and compute
    options on Google Cloud

    View full-size slide

  4. Proprietary + Confidential
    FaaS
    App platform
    Container
    Virtual machine
    The serverless spectrum
    Dedicated server
    Physical
    hardware
    Virtual
    hardware
    Operation
    system
    Application
    runtime
    Application
    Function
    Virtual
    hardware
    Operation
    system
    Application
    runtime
    Application
    Function
    Operation
    system
    Application
    runtime
    Application
    Function
    Application
    Function Function
    Serverless Zone

    View full-size slide

  5. Proprietary + Confidential
    The serverless models and characteristics
    Operational
    Model
    Programming
    Model
    No Infra Management Managed Security Pay only for usage
    Service-based Event-driven Stateless

    View full-size slide

  6. Proprietary + Confidential
    Cloud Functions
    Serverless functions
    App Engine
    Web applications and APIs
    Cloud Run
    Containerized HTTP workloads
    Serverless compute options on Google Cloud
    Source-based deployments
    of event-driven functions
    Source and compiled deployments
    of web apps and web API backends
    Containerized applications serving HTTP
    requests, fully managed or on GKE clusters

    View full-size slide

  7. Proprietary + Confidential
    Cloud Functions

    View full-size slide

  8. Proprietary + Confidential
    Cloud Functions
    Cloud services “glue”
    Backend code that
    reacts to events
    ● Background events
    ● HTTP events
    Use cases
    ● Integrating with 3rd-party
    services & APIs
    ● IoT backends
    ● Lightweight real-time
    data processing
    ● Virtual assistants & chatbots
    Available runtimes
    ● Node.JS
    ● Python
    ● Go
    ● Java
    ● .Net
    ● Ruby

    View full-size slide

  9. Proprietary + Confidential
    The cloud “glue” — Functions event sources
    Cloud Storage
    Cloud Pub/Sub
    HTTPS
    Firebase
    Cloud Scheduler
    Cloud Tasks

    View full-size slide

  10. Proprietary + Confidential
    ✅ Good fit? — ❌ Constraints?
    ✅ Good fit
    ● Easy to deploy bits of code
    ● React to Pub/Sub & Storage events
    ● Nice for webhooks handlers or other
    asynchronous operations
    ● Don’t want to think about runtime env.
    ● Lightweight data transformation (ETL)
    ● Cloud-based HTTP glue & webhooks
    ❌ Constraints
    ● Limited set of runtime languages
    ● Function granularity might be too small
    ● Must interact via events
    ● No custom domain (not out of the box)
    ● Concurrency level of 1 (more cold starts)
    ● Not for user-facing APIs or web fronts

    View full-size slide

  11. Proprietary + Confidential
    Demo — Cloud Functions

    View full-size slide

  12. Proprietary + Confidential
    App Engine

    View full-size slide

  13. Proprietary + Confidential
    App Engine Standard
    Available language runtimes:
    ● Python 2.7 / 3.7 / 3.8 / 3.9
    ● Java 8 / 11
    ● Node.js 10 / 12 / 14
    ● PHP 5.5 / 7.2 / 7.3 / 7.4
    ● Ruby 2.5 / 2.6 / 2.7
    ● Go 1.11 / 1.12 / 1.13 / 1.14 / 1.15
    Features:
    ● Multiple services, multiple versions
    ● Traffic splitting
    (A/B testing, blue/green, canary deploym.)
    ● Concurrency (80 concurrent requests)
    ● Custom domains
    ● Built-in CDN for static asset serving
    ● Batteries included
    (Memcache, Datastore…)

    View full-size slide

  14. Proprietary + Confidential
    ✅ Good fit? — ❌ Constraints?
    ✅ Good fit
    ● For stateless applications
    ● For HTTP request/response workloads
    ● Scaling high traffic, down to zero
    (good enough for Snapchat!)
    ● Built-in CDN static asset serving
    ● Traffic splitting
    (across services & versions)
    ❌ Constraints
    ● Must use one of the available runtimes
    ● No support for Web Sockets, gRPC
    streaming, or Server-Sent Events

    View full-size slide

  15. Proprietary + Confidential
    Demo — App Engine

    View full-size slide

  16. Proprietary + Confidential
    Cloud Run

    View full-size slide

  17. Proprietary + Confidential
    Containers
    Any language Rich ecosystem
    Any library of base images
    Any binary
    .js .rb .go
    .py .sh …
    0 1 0
    1 0 0
    1 1 1
    Containers
    Flexibility
    Serverless
    Velocity

    View full-size slide

  18. Proprietary + Confidential
    Serverless containers with Knative and Cloud Run
    Cloud Run
    Fully managed, deploy your
    workloads and don’t see the
    cluster.
    Cloud Run on Anthos
    Deploy into Anthos, run
    serverless side-by-side with
    your existing workloads.
    Knative everywhere
    Use the same APIs and
    tooling anywhere you run
    Kubernetes with Knative.

    View full-size slide

  19. Proprietary + Confidential
    Container contract & resources
    ● Listen on 0.0.0.0 on port $PORT
    (default 8080)
    ● HTTP server must start < 4 min
    (timeout → 504)
    ● Request time < 15 min
    (default → 5 min, up to 60 min)
    ● Stateless
    (in-memory file system)
    ● Computation only within request
    (No background activity)
    ● 1 vCPU per container instance
    (configurable to 4 vCPU)
    ● 256 MiB of memory up to a max of 8 GiB
    (configurable, soon 16 GiB)
    ● 80 concurrent requests per container
    (configurable 1-80, soon 250)
    ● 100 max containers by default
    (configurable 1-1000, support overridable)
    ● Access to a Metadata Server
    ● Sandboxed by gVisor

    View full-size slide

  20. Proprietary + Confidential
    Pay per use
    CPU / Memory / Requests 100ms

    View full-size slide

  21. Proprietary + Confidential
    Billable time
    Instance
    Billable Time
    Request 1 Start Request 1 End
    Request 2 Start Request 2 End
    Instance Time
    Billable
    Non-billable

    View full-size slide

  22. Proprietary + Confidential
    Concurrency model
    concurrency = 1
    concurrency = 80

    View full-size slide

  23. Proprietary + Confidential
    ✅ Good fit? — ❌ Constraints?
    ✅ Good fit
    ● For stateless workloads
    ● For HTTP request / response
    ● Supports Web Sockets, gRPC,
    Server-Sent events
    ● Scale up quickly, and down to zero
    ● Specific runtime needs
    (language, dependencies, binary…)
    ● Custom domains
    ❌ Constraints
    ● Must use containers, adds complexity
    ● Decide on build process
    (Cloud Build, Cloud Native Buildpacks…)
    ● No built-in CDN, or Memcache

    View full-size slide

  24. Proprietary + Confidential
    Demo — Cloud Run

    View full-size slide

  25. Proprietary + Confidential
    Hosting Web APIs on
    Serverless products
    on Google Cloud

    View full-size slide

  26. Proprietary + Confidential
    Cloud Functions
    Good for simple single URL
    endpoints, for asynchronous
    calculations, or for
    webhooks callbacks
    Not for full blown Web APIs,
    synchronous calls (user
    waiting for cold start)
    No custom domain for nice
    Web API URLs
    Several hosting options, where to host my Web APIs?
    App Engine
    Great for deploying Web
    APIs, using one of the
    available language runtime
    Built-in static assets handy
    for serving API media files
    Services & versioning is
    useful for API versioning
    Custom domain useful for
    nice Web API URLs
    Cloud Run
    Any Web API framework and
    runtime in a container
    Support gRPC APIs, as well
    as Web Sockets and
    Server-Sent Events
    Services & revision can be
    used for API versioning
    Custom domain useful for
    nice Web API URLs

    View full-size slide

  27. Proprietary + Confidential
    An API gateway to rule them all!
    Provide a consistent and well-defined API
    contract (Open API) over existing Web APIs
    made of several services implemented in
    various languages, deployed on different
    serverless platforms
    Features
    ● Decouple API contract & usage from
    underlying implementation
    ● Regroup several deployed services
    under a common REST API
    ● Manage API keys, JWT tokens, user
    authentication
    ● Define rate limitations
    ● Serverless gateway (scale to zero)

    View full-size slide

  28. Proprietary + Confidential
    Web API design
    and best practices

    View full-size slide

  29. Proprietary + Confidential
    REST — Principled design of the modern Web architecture
    Representational State Transfer, invented by Roy Field
    Architectural properties
    ● Performance
    ● Scalability
    ● Simplicity
    ● Modifiability
    ● Visibility
    ● Portability
    ● Reliability
    Architectural constraints
    ● Client-server
    ● Stateless
    ● Cacheable
    ● Layered system
    ● Code on demand (optional)
    ● Uniform interface

    View full-size slide

  30. Proprietary + Confidential
    REST — Uniform interface
    Identification of resources
    Manipulation of resources
    through representations
    Self-descriptive messages
    HATEOAS
    (Hypermedia As The Engine of Application State)
    Resource as URIs: http://api.co/cars/123
    JSON, XML, YAML, HTML…
    (and other media types)
    HTTP GET, POST, PUT, DELETE, PATCH
    Hypermedia: HAL, JSON-LD, Siren

    View full-size slide

  31. Proprietary + Confidential
    HTTP methods & URIs for collections / items
    Item
    http://api.co/v2/cars/1234
    Collection
    http://api.co/v2/cars
    GET Retrieve a specific car List all the cars
    POST
    Create a new car if allowed to specify its
    ID or key, or an ERROR
    Create a new car
    PUT Update a specific car
    Replace the entire collection with a whole
    news list of cars
    PATCH Update some details of a specific car
    Update a batch of the cars in the list,
    or an ERROR
    DELETE Delete a specific car Delete all the cars
    Priority
    operations

    View full-size slide

  32. Proprietary + Confidential
    Nouns refer to resources
    Resources are handled with HTTP verbs:
    ● GET /cars/123, not /getCar/123
    ● POST /cars, not /createCar
    ● DELETE /cars/1,
    not POST /deleteCar/1
    Prefer nouns over verbs!
    Verbs can be used for actions or calculations:
    ● /login, /logout
    ● /convert — convert temp. °C ⇆ °F
    ● /transcode — a video into another format
    ● /promote — a release, and employee...

    View full-size slide

  33. Proprietary + Confidential
    Naming conventions → Singular or plural resources?
    Prefer plural forms:
    /tickets/123 not /ticket/123
    Avoid confusing odd singular vs plural forms
    ● /person vs /people, or /goose vs /geese
    Easier for URL routing: same prefix for regular expressions
    Think of it as: “this is the 123th item of the tickets collection”

    View full-size slide

  34. Proprietary + Confidential
    Different casing in the wild:
    ● UpperCamelCase or lowerCamelCase
    ● snake_case or dashed-snake-case
    Prefer lowercase and snake case
    (underscores seem more commonly used)
    Naming conventions → Different casings
    But chose one casting
    and stick with it!

    View full-size slide

  35. Proprietary + Confidential
    Dealing with hierarchies & relationships in URIs
    ✅ /tickets/123/messages/4
    a ticket could be a group of messages
    ❌ /usergroups/234/users/67
    a user could belong to different user groups
    a user should have a URI of its own, referenced from the usergroup payload

    View full-size slide

  36. Proprietary + Confidential
    Prefer unwrapped collections
    ● Unless there’s specific collection
    payload metadata (ex: a category, a
    label, a time information…)
    ● Pagination is better handled
    with HTTP headers
    (Un)Wrapped collections
    GET /tickets
    {
    data: [
    { id: 1, … }
    ]
    }
    GET /tickets
    [
    { id: 1, … }
    ]

    View full-size slide

  37. Proprietary + Confidential
    Path — required, resource identifier
    /books/123
    Query — optional, query collections
    /books/123?page=3
    API parameters, a rule of thumb
    Body — resource specific logic
    Part of the payload
    Header — global, platform wide
    X-Client-ID: abc123

    View full-size slide

  38. Proprietary + Confidential
    Time for a cat break?
    HTTP Status Cats!

    View full-size slide

  39. Proprietary + Confidential
    HTTP status codes
    Use appropriate HTTP status codes
    when answering requests
    Not just 200, 300, 400, 500...
    ● 1xx — Hold on!
    ● 2xx — Here you go!
    ● 3xx — Go away!
    ● 4xx — You messed up!
    ● 5xx — I messed up!

    View full-size slide

  40. Proprietary + Confidential
    HTTP status codes → Common status codes
    300 Multiple Choices
    301 Moved Permanently
    302 Found
    303 See Other
    304 Not Modified
    307 Temporary Redirect
    308 Permanent Redirect
    200 OK
    201 Created
    202 Accepted.
    204 No Content
    206 Partial Content
    400 Bad Request
    401 Unauthorized
    403 Forbidden
    404 Not Found
    405 Method Not Allowed
    406 Not Acceptable
    409 Conflict
    410 Gone
    412 Precondition Failed
    415 Unsupported Media Type
    416 Requested range unsatisfiable
    429 Too Many Requests
    500 Internal Server Error
    501 Not Implemented
    502 Bad Gateway
    503 Service Unavailable
    504 Gateway Time-out
    506 Variant Also Negotiates
    509 Bandwidth Limit Exceeded

    View full-size slide

  41. Proprietary + Confidential
    HTTP status codes → 2xx — 201 Created
    When a resource is created, return 201
    Specify a Location header, pointing at the
    location of the newly created resource
    POST /cars …
    HTTP/1.1 201 Created
    Location: http://api.co/v2/cars/2543
    API navigation is important
    to make the API more discoverable

    View full-size slide

  42. Proprietary + Confidential
    HTTP status codes → 2xx — 202 Accepted
    Request accepted but might be handled asynchronously
    It can be a long-running operation, yielding a result later on
    (should return a payload representing that operation
    or have a Location header pointing at the operation for further status requests)
    POST /jobs …
    HTTP/1.1 202 Accepted

    View full-size slide

  43. Proprietary + Confidential
    Response ok, but no payload is returned
    DELETE /tickets/234
    HTTP/1.1 204 No content
    The resource was successfully deleted, no need for a return payload.
    But could return 200 with the payload representing the deleted object.
    HTTP status codes → 2xx — 204 No content

    View full-size slide

  44. Proprietary + Confidential
    When the content is too big to be returned in one response:
    ● A resource payload that is too big
    ● A collection payload that is paginated
    GET /meteorites?page=4
    HTTP/1.1 206 Partial content
    Link: ; rel=”first”,
    ; rel=”prev”,
    ; rel=”next”,
    ; rel=”last”,
    HTTP status codes → 2xx — 206 Partial content

    View full-size slide

  45. Proprietary + Confidential
    With a page number — ?page=3
    ● Can also specify a page size
    ● Might get odd results on collection insertions
    With a cursor — ?cursor=abc123
    ● Insertion friendly
    With a semantic parameter — ?letter=A
    ● For a limited or discrete number of elements
    Pagination

    View full-size slide

  46. Proprietary + Confidential
    Accept-Range header could be used
    (not just for bytes, but not very common)
    GET /users
    HTTP/1.1 206 Partial content
    Accept-Ranges: users
    Content-Range: users 0-9/200
    Pagination with an Accept-Range header
    GET /users
    Range: users=30-39
    HTTP/1.1 206 Partial content

    View full-size slide

  47. Proprietary + Confidential
    When HTTP caching headers are in play, the client should have a version in cache already
    GET /meteorites/654
    HTTP/1.1 304 Not modified
    HTTP status codes → 3xx — 304 Not modified

    View full-size slide

  48. Proprietary + Confidential
    Request with Modified-Since and reply with Last-Modified
    GET /users/123
    Modified-Since: Wed, 7 Apr 2021 01:16:10 GMT
    HTTP/1.1 200 OK
    Last-Modified: Wed, 15 Apr 2021 09:16:10 GMT
    Caching → Last-Modified (date based)

    View full-size slide

  49. Proprietary + Confidential
    Request with If-None-Match
    and reply with Etag
    GET /users/123
    If-None-Match: e9fea8ca2fbb4e6c
    HTTP/1.1 200 OK
    Etag: 686897696a7c876b
    Caching → ETag (tag based)
    GET /users/123
    If-None-Match: 686897696a7c876b
    HTTP/1.1 304 Not modified

    View full-size slide

  50. Proprietary + Confidential
    Provide helpful error payloads
    No definitive standard yet
    ● HTTP problem proposal
    ● vnd-error mime type
    HTTP status codes → 4xx — Errors
    HTTP/1.1 403 Forbidden
    Content-Type: application/problem+json
    {
    "type": "https://ex.com/probs/out-of-credit",
    "title": "Not have enough credit.",
    "detail": "Current balance: 30, cost: 50.",
    "instance": "/account/12345/msgs/abc",
    "balance": 30,
    "accounts": ["/account/12345"]
    }

    View full-size slide

  51. Proprietary + Confidential
    An unknown status code should be treated as the first one of the family
    ● 4xx → 400 generic client error
    ● 5xx → 500 generic server error
    HTTP status codes → 4xx / 5xx

    View full-size slide

  52. Proprietary + Confidential
    When rate limitation is reached, send 429 Too Many Requests
    Otherwise, indicate common rate limitation status headers:
    HTTP/1.1 200 OK
    Date: Mon, 01 Jul 2020 17:27:06 GMT
    X-RateLimit-Limit: 60
    X-RateLimit-Remaining: 56
    X-RateLimit-Reset: 1372700873
    HTTP status codes → 4xx — 429 Too Many Requests

    View full-size slide

  53. Proprietary + Confidential
    Selecting
    ● Query
    parameters
    One size does not fit all!
    Filtering
    ● Include fields
    ● Exclude fields
    ● Expand fields
    ● Style
    preference
    Sorting
    ● Query
    parameters
    Searching
    ● Combine
    filtering, sorting,
    selecting…
    ● Custom query
    language

    View full-size slide

  54. Proprietary + Confidential
    Selecting with query parameters:
    GET /restaurants?type=chinese&stars=5
    Expanding referenced resources:
    GET /users/123?fields=address.zip
    Selecting

    View full-size slide

  55. Proprietary + Confidential
    Include only fields you’re interested in
    GET /users/123?fields=name,age
    Specify excluded fields
    GET /users/123?exclude=biography
    Specify a “style” as a query parameter
    GET /users/123?style=compact
    Filtering
    Use the prefer header for different “styles”
    GET /users/123 HTTP/1.1
    Content-Type: application/json
    Prefer: return=minimal
    Vary: Prefer,Accept,Accept-Encoding
    HTTP/1.1 200 OK
    Content-Type: application/json
    Vary: Prefer,Accept,Accept-Encoding
    Preference-Applied: return=minimal

    View full-size slide

  56. Proprietary + Confidential
    SQL style
    GET /books?sort=title+DESC
    GET /books?sort=title+DESC,author+ASC
    Sort and asc/desc query parameters
    GET /books?sort=title&order=DESC
    GET /books?sort=title,authors&desc=title&asc=author
    Sorting

    View full-size slide

  57. Proprietary + Confidential
    Combine various mechanisms:
    filtering fields, ordering, pagination…
    Other approaches
    like GraphQL...
    Searching
    Provide a full-blown query language
    ● POST a query document
    to a /search endpoints
    ● Encode a query into a query parameter

    View full-size slide

  58. Proprietary + Confidential
    ● Most frequent, in the URL
    GET /v2/cars/123
    ● Custom header
    GET /cars/123
    X-API-Version: 2
    Versioning: different approaches
    ● Less frequent, with an accept header
    Clients don’t have to change endpoint, but
    update headers
    GET /cars/123
    Accept: application/vnd.cars.v2/json

    View full-size slide

  59. Proprietary + Confidential
    With hypermedia controls:
    ● Easier discovery & navigation
    ● More generic API clients
    ● Can palliate need for versioning
    However:
    ● Heavier payloads (for limited bandwidth)
    ● Clients still need to understand the meaning of “links”
    ● Many competing hypermedia formats
    ○ HAL, JSON-LD, Collection+JSON, SIREN...
    Hypermedia — The Richardson’s API maturity model

    View full-size slide

  60. Proprietary + Confidential
    Frameworks provide custom Web API documentation approach
    Also often generate Open API documentation and playground
    Open API 2 still dominant (also known as Swagger)
    But Open API 3.1 released (→ check tooling support)
    Other (less popular) formats exist, like:
    ● RAML
    ● API Blueprint
    API documentation — Open API (Swagger)

    View full-size slide

  61. Proprietary + Confidential
    Hands-on — Let’s deploy serverless Web APIs!

    View full-size slide

  62. Proprietary + Confidential
    You’ll find step by step instructions
    in this codelab:
    codelabs.developers.google.com/
    codelabs/serverless-web-apis
    Codelabs instructions

    View full-size slide

  63. Proprietary + Confidential
    You’ll find the code used
    in the codelabs on Github:
    github.com/glaforge/
    serverless-web-apis
    Open source code

    View full-size slide

  64. Proprietary + Confidential
    REST API design resources
    The never ending REST API design debate
    https://speakerdeck.com/glaforge/
    the-never-ending-rest-api-design-debate-devoxx-france-2016
    Google API design guide
    https://cloud.google.com/apis/design
    Best practices for REST API design
    https://stackoverflow.blog/2020/03/02/best-practices-for-rest-api-design/
    API design guidance: long-running background jobs
    https://tyk.io/api-design-guidance-long-running-background-jobs/
    Best practices for designing a pragmatic RESTful API
    https://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
    PayPal REST API guide
    https://github.com/paypal/api-standards/blob/master/api-style-guide.md
    How to design a REST API
    https://blog.octo.com/en/design-a-rest-api/
    HTTP API design guide (initially from Heroku)
    https://geemus.gitbooks.io/http-api-design/content/en/index.html
    On choosing a hypermedia type for your API
    https://sookocheff.com/post/api/on-choosing-a-hypermedia-format/
    Your API versioning is wrong, by Troy Hunt
    https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/

    View full-size slide

  65. Proprietary + Confidential
    Thank you!
    Guillaume Laforge — @glaforge
    Developer Advocate
    Google cloud

    View full-size slide