@fastify/aws-lambda

repository·main·Indexed 20 days ago

https://github.com/fastify/aws-lambda-fastify

A library for running Fastify web applications on AWS Lambda. It utilizes Fastify's inject function instead of internal sockets for improved efficiency. Features include support for binary responses via base64 encoding, AWS Lambda response streaming with payloadAsStream, and the ability to access Lambda event and context objects within Fastify requests. Version 6.4.1.

Tokens
2.3K
Snippets
7
Records
11
Agent score
19%

What's inside @fastify/aws-lambda

  1. Handle binary responses and compression

    main

    API Gateway requires binary responses to be base64-encoded. @fastify/aws-lambda handles this via two methods:

    1. binaryMimeTypes: An allowlist of Content-Type values (e.g., image/png).
    2. enforceBase64: A custom function for logic-based encoding.

    Note: If you provide a custom enforceBase64 function, it replaces the built-in default (which automatically handles compressed responses like gzip or br). If you still want compression-based encoding, you must re-implement that check in your custom function.

    // Example: Custom rule for binary detection
    exports.handler = awsLambdaFastify(app, {
      binaryMimeTypes: ['application/octet-stream', 'image/png'],
      enforceBase64: (res) => {
        if (res.headers['content-type'] === 'application/x-protobuf') return true
        const enc = res.headers['content-encoding']
        return !!enc && enc !== 'identity'
      }
    })
  2. Considerations when using @fastify/aws-lambda

    main

    When deploying Fastify on AWS Lambda using this package, keep the following architectural constraints in mind:

    • Cold Starts: Apps that do not receive frequent traffic may experience cold starts.
    • Statelessness: The application must be stateless.
    • Timeouts:
      • If using API Gateway, there is a hard timeout of 29 seconds.
      • If using Application Load Balancer (ALB), there is no timeout limit from the load balancer, but you are still bound by the Lambda maximum execution time (15 minutes).
    • Framework Alternatives: If you are using a framework other than Fastify (e.g., Express, Koa, Hapi), consider using serverless-http or serverless-adapter instead.
  3. Reduce cold start latency with top-level await

    main

    When using Node.js 14+ with ES Modules, you can lower cold start latency by calling await app.ready() outside of the Lambda handler. This ensures the Fastify instance is fully initialized before the first request arrives.

    import awsLambdaFastify from '@fastify/aws-lambda'
    import app from './app.js'
    
    export const handler = awsLambdaFastify(app)
    await app.ready() // Must be placed after awsLambdaFastify call
  4. Implement response streaming with payloadAsStream

    main

    To use AWS Lambda response streaming, set payloadAsStream: true in the options and use awslambda.streamifyResponse. This allows you to pipe a Fastify response stream directly to the Lambda response stream.

    import awsLambdaFastify from '@fastify/aws-lambda'
    import { promisify } from 'node:util'
    import stream from 'node:stream'
    import app from './app.js'
    
    const pipeline = promisify(stream.pipeline)
    const proxy = awsLambdaFastify(app, { payloadAsStream: true })
    
    export const handler = awslambda.streamifyResponse(async (event, responseStream, context) => {
      const { meta, stream } = await proxy(event, context)
      responseStream = awslambda.HttpResponseStream.from(responseStream, meta)
      await pipeline(stream, responseStream)
    })
    
    await app.ready()
  5. Handle binary responses and Base64 encoding

    main

    The library automatically determines if a response should be Base64 encoded based on the Content-Type and the binaryMimeTypes option.

    By default, it also treats compressed responses (where content-encoding is present and not identity) as binary. You can customize this behavior using:

    • binaryMimeTypes: An array of MIME types to always encode.
    • enforceBase64: A custom function passed via options to decide if a response should be encoded.
    • disableBase64Encoding: A function to explicitly disable encoding for certain events (e.g., when using payloadAsStream).
  6. Configure @fastify/aws-lambda options

    main

    You can pass an options object to awsLambdaFastify(app, options) to customize its behavior.

    Key options include:

    • binaryMimeTypes: Array of Content-Type values to treat as binary (base64-encoded for API Gateway).
    • enforceBase64: Function (res) => boolean to decide if the response body should be base64-encoded. If omitted, it defaults to encoding any response with a non-identity Content-Encoding (e.g., gzip, br).
    • decorateRequest: Boolean (default true) that determines if the Lambda event and context are attached to the Fastify request.
    • payloadAsStream: Boolean (default false). If true, the response is a stream, enabling use with awslambda.streamifyResponse.
    • serializeLambdaArguments: Boolean (default false). If true, serializes Lambda Event and Context into x-apigateway-event and x-apigateway-context headers.
  7. Wrap a Fastify instance for AWS Lambda

    main

    To use a Fastify application in AWS Lambda, import the default export from @fastify/aws-lambda and call it with your Fastify instance and an optional configuration object. This returns a handler function compatible with the AWS Lambda runtime.

    const fastify = require('fastify')()
    const awsLambdaFastify = require('@fastify/aws-lambda')
    
    fastify.get('/', async (request, reply) => {
      return { hello: 'world' }
    })
    
    // The returned function is your Lambda handler
    const handler = awsLambdaFastify(fastify, { /* options */ })
    
    module.exports.handler = handler
    const fastify = require('fastify')()
    const awsLambdaFastify = require('@fastify/aws-lambda')
    
    fastify.get('/', async (request, reply) => {
      return { hello: 'world' }
    })
    
    const handler = awsLambdaFastify(fastify)
    
    module.exports.handler = handler
  8. Access Lambda Event and Context in Fastify

    main

    By default, the original Lambda event and context are decorated onto the Fastify request object under request.awsLambda.

    If decorateRequest is set to false, or if you prefer using headers, you can access them via the serializeLambdaArguments: true option, which places them in x-apigateway-event and x-apigateway-context headers.

    // Access via request decoration (default)
    app.get('/', (request, reply) => {
      const event = request.awsLambda.event
      const context = request.awsLambda.context
    })
    
    // Access via headers (if serializeLambdaArguments: true)
    app.get('/', (request, reply) => {
      const event = JSON.parse(decodeURIComponent(request.headers['x-apigateway-event']))
      const context = JSON.parse(decodeURIComponent(request.headers['x-apigateway-context']))
    })
  9. Performance metrics for @fastify/aws-lambda

    main

    Benchmarks indicate that @fastify/aws-lambda provides high throughput for AWS Lambda environments. The fastest configurations are @fastify/aws-lambda with decorateRequest: false or the default configuration.

    Performance Comparison (ops/sec):

    • @fastify/aws-lambda (decorateRequest: false): ~56,892 ops/sec
    • @fastify/aws-lambda: ~56,571 ops/sec
    • @fastify/aws-lambda (serializeLambdaArguments: true): ~56,499 ops/sec
    • serverless-http: ~45,867 ops/sec
    • aws-serverless-fastify: ~17,937 ops/sec
    • serverless-express: ~16,647 ops/sec
  10. Access AWS Lambda event and context from Fastify request

    main

    If decorateRequest is enabled (default), you can access the original AWS Lambda event and context directly from the Fastify request object using the property name specified in decorationPropertyName (defaults to awsLambda).

    This is useful for accessing metadata like requestContext or specific Lambda context properties within your route handlers.

    fastify.get('/info', async (request, reply) => {
      const { event, context } = request.awsLambda
      return { requestId: event.requestContext.requestId }
    })