Serverless: HTTP API Support

Created on 5 Dec 2019  Â·  48Comments  Â·  Source: serverless/serverless

Support HTTP API:

https://aws.amazon.com/blogs/compute/announcing-http-apis-for-amazon-api-gateway/


Proposal of a configuration schema within a Serverless Framework

_Note: This proposal is "live" (updated in place whenever there's an agreement on changes to it)_

provider:
  # (optional) general API settings 
  httpApi:
    id: xxx # Attach to existing, already deployed, HTTP API id
    timeout: 5 # Default timeout for endpoints
    # Following options are supported only for HTTP API's to be created in context of this service
    cors: # Can also be set to `true` which will apply below defaults. If not set, there's no CORS
      allowedOrigins: "*"
      allowedHeaders: "*"
      allowMethods: "*"
      allowCredentials: true
      exposedResponseHeaders: "*"
      maxAge: 300

    authorizers:
      # JWT authorizers
      jwtAuthorizer:
        identitySource: $request.header.Authorization
        issuerUrl: <url>
        audience:
          - <audience1>
          - <audience2>

  # (optional) access logging for HTTP API 
  logs:
    httpApi: # Can also be set to `true` which will apply below defaults. If not set, no logs are written
      format: '{ "requestId":"$context.requestId", "ip": "$context.identity.sourceIp", "requestTime":"$context.requestTime", "httpMethod":"$context.httpMethod","routeKey":"$context.routeKey", "status":"$context.status","protocol":"$context.protocol", "responseLength":"$context.responseLength" }'

functions:
  # Individual HTTP route example
  users:
    handler: users.handler
    events:
      - httpApi:
          path: /users
          method: GET # Can be "*" as a catch-all for all HTTP methods for given path
          timeout: 5 # Optional, timeout in seconds
          authorizer: # Optional, if not set, endpoint is public
            name: jwtAuthorizer
            scopes:
              - user.id
              - user.email

  # Catch all other routes example
  api:
    handler: api.handler
    events:
      - httpApi:
          path: "*" # Once deployed, cannot be removed

In addition support for importing Open API objects can be added as:

provider:
  httpApi:
    # Endpoints configuration provided via Open API object
    openApi: # can be imported as e.g. ${file(open-api.json)}
      openapi: "3.0.0"
      info:
        title: "HTTP API example"
        version: "1.0.0"
      paths:
        /users:
          get:
            operationId: usersGet
          post:
            operationId: usersPost
        /other:
          get:
            operationId: other

functions:
  # Individual HTTP route example
  users:
    handler: users.handler
    events:
      - httpApi:
          operationId: usersGet # Match endpoint specified within Open API object
  # Catch all other specified routes example
  api:
    handler: api.handler
    events:
      - httpApi:
          operationId: "*"

Implementation roadmap

Implement and publish HTTP API support in following stages:

  1. [x] Basic routes support, no cors, no authorizers, no open API objects import (#7274, #7331 & #7383)
  2. [x] CORS support (#7336)
  3. [x] JWT authorizers support (#7346)
  4. [x] Access logs (#7385)
  5. [x] Support existing HTTP API's (#7396)
  6. [x] Support timeout setting (#7401)
  7. [ ] (eventually) Open API object support - possibly leave out for community to implement (when demand shows)
caaws-event-http-api feature

Most helpful comment

@jplock We we will propose an implementation spec proposal next week, and actual implementation work should follow up shortly after we agree on most important details.

All 48 comments

+1

+1

+1

I believe the challenge will be supporting the other event types, if you have 1 lambda with 2 events of type http and type SQS, it will have to create 2 different api gateways right? One for the HTTP API event and another in the old format for the SQS event. So there will be 2 different api gateways for the same function..

I would just reject the configuration.

In my opinion, you would configure which API to use in the configuration file. If there are some features used which are not supported, the configuration should be rejected.

Only HTTP events need API Gateway configuration. All the other event types have their own event configuration that don't go through API Gateway.

You'd only ever require both a v1 and v2 API Gateway config if you specifically wanted events in both (v1 does have a lot more features than v2… but the downside is cost and latency).

Looks like CloudFormation support just landed: https://aws.amazon.com/about-aws/whats-new/2019/12/aws-cloudformation-updates-for-api-gateway-codepipeline-s3-iam-ecs-rds-es-lambda-and-more/

Create an HTTP API, JSON web tokens (JWTs) Authorizer and stage for HTTP API, and specify VPC endpoint IDs of an API to create Route53 aliases in Amazon API Gateway.

+1

+1

It’s agonizing to wait months for new features to be added to infrastructure as code tools

@bionicles if it's so urgent for you, create a PR - it's open source community project. What are you waiting for?

@medikoo @pmuens could we get some guidenance from the Serverless team on how you might like this to work if somewhere were to create a PR for your review? Would you like to only support http endpoints and reject the configuration if there are other event types, etc.?

@jplock We we will propose an implementation spec proposal next week, and actual implementation work should follow up shortly after we agree on most important details.

@hakimio Downvote as you wish but it’s unfair to expect folks who’ve never made a PR on a large software project to learn the inner workings of a codebase to add critical features for free. The maintainers of the repo are responsible for the code within, not new users.

There are a lot of options for infrastructure as code today (Pulumi, CDK, Terraform, Cloudformation, SAM) ... and “Serverless” appears to be a for-profit business, so surely independent unpaid developers are not expected to provide core functionality?

We’d all prefer this feature were added by someone who had already contributed to the repo. Sorry if my disappointment with the delay hurt your feelings.

Thanks for the downvotes, it’s fun to strike a nerve

Accidentally closed while trying to comment, apologies.

I've updated the main description of this issue with a proposal of configuration we can use within a Framework (leaving implementation details aside).

Let us know what you think, we want to follow with implementation shortly.

Awesome. How about the $default stage? https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-concepts.html#http-api-concepts.stages

Are we able to use $default stage by specifying provider.stage as $default? Or should we manually specify Stage at the resources section?

Are we able to use $default stage by specifying provider.stage as $default? Or should we manually specify Stage at the resources section?

Idea is to map current stage setting (which by default is dev). So technically no support for $default. Do you see it as big shortcoming?

Not for my use case. But some folks might be interested in it since it is one of main changes in ApiGatewayV2.

Maybe it is just simple as setting $default as a stage name? (I can't test it right now so not sure) https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-httpapi.html

Pull request with first stage of support, can be tracked at https://github.com/serverless/serverless/pull/7274

Thoughts on keeping it under http, with a restApi flag that first defaults to true, but can be set to false to enable this ^, with a deprecation warning that you need to add restApi: true to keep behaviour?

- http:
    restApi: false # explicit for first release, if true or omitted, current behaviour
    path: /

<emit warnings> and after a release or two:

- http:
    restApi: true|false # force users to migrate existing APIs to explicitly enable restApi? or check current state to detect..
    path: /

<some period of time>

- http:
    restApi: false # new default
    path: /

I like using a new event type for this

Can we get rid of the ApiStage Resource entirely? serverless creates a new api for every stage so I don't see a point of having /dev in the url as well. And if someone needs the stage then it can simply be added as a Resource.

But having a clean url by default would be nice and it would reduce the configuration.
In fact I removed this.compileStage(); from the HttpApiEvents constructor and besides serverless not knowing the url at the end: it worked flawlessly.

@Nemo64 good point. The only issue I see, is that it would make now a breaking change (with minor version change, urls of already deployed API's will suddenly change).

Maybe let's keep it then for v2, which afaik we should publish soon

@Nemo64 we've just discussed that internally, and we decided to not hold back, and drop stage (on HTTP APIs) with next minor release (as support is still in early stage, and we didn't communicate it broadly)

It means it may break already deployed API's. If it appears as real concern for anyone please raise.

@Nemo64 it's addressed with this PR: https://github.com/serverless/serverless/pull/7331

Thanks for the fast implementation!
I'd love to see the openapi support next

I may have missed something. How do I get at attributes provided in the (encrypted) JWT from inside the handler ?
In short, where are the docs ?

I may have missed something. How do I get at attributes provided in the (encrypted) JWT from inside the handler ?
In short, where are the docs ?

@tomchiverton
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html

After validating the JWT, API Gateway passes the claims in the token to the API route’s integration. Backend resources, such as Lambda functions, can access the JWT claims in $context.authorizer.claims.

I don't think serverless-offline supports it yet, though. Don't quote me on that.

I'd love to see the openapi support next

@jgroom33 thanks for raising. Do you have an Open API spec of endpoints to which you'd like to refer in serverless.yml file (as proposed in implementation spec in main description of an issue) ?

I'd prefer the implementation that is specified (external swagger.yml)
On a related topic, it would be great to do serverless codegen from a swagger spec.
Swagger server codegen could produce the following (assuming petstore API):
serverless.yml file
pet-handler.py (handles post/delete/etc)

I'd prefer the implementation that is specified (external swagger.yml)

So this is what is proposed in main description (have you read it?)

On a related topic, it would be great to do serverless codegen from a swagger spec.

Generator that will create an serverless.yml configuration with placeholder lambdas (?)
Sounds as good next step.

This breaking change needed to wait until v2, I'd recommend it gets rolled back.

Or at a minimum it needs to be clearly marked as a breaking change everywhere people check release notes (at a minimum on https://github.com/serverless/serverless/releases) and some effort should be put into documenting how people can upgrade and deploy without it forcing a change to APIs.

A good example of what I'd like this to look like can be seen at https://github.com/vuetifyjs/vuetify/releases/tag/v2.1.9. Big warning sign, "BREAKING CHANGES" in caps, documentation about what broke, who will be impacted, and how to fix it.

You've broken all our deployments. You need to roll this back. Any change that changes deployed API end points needs to be clearly flagged well in advance.

So that's now 5 for, 2 against. Hardly clear cut.

Important notice: If you rely on catch all route (*) unfortunately there's a breaking change coming.

Currently catch-all route is configured through AWS::ApiGatewayV2::Api resource (as AWS provided a shortcut, that allows to generate auto deployed default stage with default route, without a need to configure dedicated resources for that)

Still I learned that configuring default stage and default route like that while works well for demo purposes is not convenient for real world scenarios due to following implications:

  • Default stage, setup that way, cannot be enriched with access log settings (via CloudFormation means)
  • There's no way to restrict access (via JWT authorizer) to default route setup that way (via CloudFormation means)
  • Default route, setup that way, cannot be removed

And unfortunately stack deployed with that, cannot be updated to switch to configuration that specifically configures default stage and default route. That means to update you'll need to remove the service and create it again.

I think it's best to publish patch that brings us on right track early and minimize the breakage across eventually deployed services.

Pull request with a fix is here: https://github.com/serverless/serverless/pull/7383 I plan to be publish it tomorrow with v1.64.1

@medikoo is there any way to configure the TimeoutInMillis property on the AWS::ApiGatewayV2::Integration resources? It seems that AWS defaults HTTP APIs to a 5000ms timeout. I'm generating binary responses in one of my Lambdas and would like to crank it up. The timeout property in the provider section of serverless.yml doesn't seem to do anything.

@medikoo is there any way to configure the TimeoutInMillis property on the AWS::ApiGatewayV2::Integration resources?

@mattbarry very good question. We will shortly add this, as indeed it should be configurable

@medikoo is there any way to configure the TimeoutInMillis property on the AWS::ApiGatewayV2::Integration resources?

@mattbarry very good question. We will shortly add this, as indeed it should be configurable

That would be great! 5 seconds isn't very long if you're waiting for a cold start on a C# or Java Lambda.

@medikoo why hasn't it been published/documented anywhere that upgrading to 1.64.0 (and beyond) causes API's to change?

Or am I missing something?

@medikoo why hasn't it been published/documented anywhere that upgrading to 1.64.0 (and beyond) causes API's to change?

We've announced that here: https://github.com/serverless/serverless/issues/7052#issuecomment-584870376 and in changelog.

At this point there was no other announcements about HTTP API aside this issue and version Changelog.

@medikoo Is this only a breaking change if we've explicity set serverless.yml to use httpApi within the provider?

If so, then it makes sense to me to push forward with it and to treat it as not a big deal.

@camhart latest breaking change affected just deployments that involve catch all route. All other remain unaffected. I've outlined it in comment above.

Anyway 1.64.1 brought last such turnover I believe. We have now really complete and stable support for HTT API, and features which were not officially published so far, will be published shortly (within 24 hours I hope) with 1.65.0

Isn't the new timeout also a possible breaking change too? https://github.com/serverless/serverless/pull/7401#issuecomment-592415779

@Nemo64 I see it more as a bug fix. I don't think it can break stuff for users, it'll rather fix things

Just wanted to say thank you. Amazing community.

I'm closing this as I consider HTTP API support being implemented in a Framework.

Although, there's one side item from description todo list, which wasn't delivered (referencing external Open API objects in serverless.yml). Please raise your demand if you find having that in valuable. PR that adds that is also highly welcome!

Was this page helpful?
0 / 5 - 0 ratings