Skip to content
You are reading the v2 docs, currently in beta.V1 docs
oRPC
Esc
↑↓navigate↵open⌘Jpreview
On this page

AWS Lambda Adapter

Use oRPC on AWS Lambda behind API Gateway (payload formats 1.0 and 2.0) and Lambda Function URLs using response streaming.

Server Usage

import type { APIGatewayProxyEventV2, AwsLambdaGlobal } from '@standard-server/aws-lambda'
import { onError } from '@orpc/server'
import { RPCHandler } from '@orpc/server/aws-lambda'
import { CORSHandlerPlugin } from '@orpc/server/plugins'

declare const awslambda: AwsLambdaGlobal

const handler = new RPCHandler(router, {
  plugins: [
    new CORSHandlerPlugin()
  ],
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

export const rpc = awslambda.streamifyResponse<APIGatewayProxyEventV2>(async (event, responseStream, context) => {
  const { matched } = await handler.handle(event, responseStream, {
    prefix: '/rpc',
    context: {} // Provide initial context if needed, can be an async function
  })

  if (matched) {
    return
  }

  awslambda.HttpResponseStream.from(responseStream, {
    statusCode: 404,
    headers: {},
    cookies: [],
  }).end('Not found')
})
import type { APIGatewayProxyEventV2, AwsLambdaGlobal } from '@standard-server/aws-lambda'
import { OpenAPIHandler } from '@orpc/openapi/aws-lambda'
import { onError } from '@orpc/server'
import { CORSHandlerPlugin } from '@orpc/server/plugins'

declare const awslambda: AwsLambdaGlobal

const handler = new OpenAPIHandler(router, {
  plugins: [
    new CORSHandlerPlugin()
  ],
  interceptors: [
    onError((error) => {
      console.error(error)
    }),
  ],
})

export const api = awslambda.streamifyResponse<APIGatewayProxyEventV2>(async (event, responseStream, context) => {
  const { matched } = await handler.handle(event, responseStream, {
    prefix: '/api',
    context: {} // Provide initial context if needed, can be an async function
  })

  if (matched) {
    return
  }

  awslambda.HttpResponseStream.from(responseStream, {
    statusCode: 404,
    headers: {},
    cookies: [],
  }).end('Not found')
})

Path Encoding

API Gateway HTTP APIs deliver the request path (rawPath in payload 2.0, path in payload 1.0) already URL-decoded, while REST APIs, ALB, and Lambda Function URLs deliver it still encoded. The handler re-escapes decoded paths before matching, so every path is decoded only once and a literal %61 in an HTTP API path stays %61 instead of becoming a.

By default ('auto'), a payload 1.0 event is treated as decoded when it carries version: '1.0' (HTTP API), and a payload 2.0 event is treated as decoded unless requestContext.domainName is a Function URL host (*.lambda-url.<region>.on.aws). Set pathEncoding to override the detection:

const handler = new RPCHandler(router, {
  /**
   * 'auto': detect from the event (default)
   * 'encoded': every path is still URL-encoded
   * 'decoded': every path is already URL-decoded
   *
   * @default 'auto'
   */
  pathEncoding: 'auto',
})

Event Stream Options

You can configure how an AsyncIteratorObject is streamed to the client using the sendStandardResponse.eventStream options when creating the handler.

const handler = new OpenAPIHandler(router, {
  sendStandardResponse: {
    eventStream: {
      initialComment: {
        /**
         * If true, an initial comment is sent immediately upon stream start to flush headers.
         * This allows the receiving side to establish the connection without waiting for the first event.
         *
         * @default true
         */
        enabled: true,
        /**
         * The content of the initial comment sent upon stream start. Must not include newline characters.
         *
         * @default ''
         */
        comment: '',
      },
      keepAlive: {
        /**
         * If true, a ping comment is sent periodically to keep the connection alive.
         *
         * @default true
         */
        enabled: true,
        /**
         * Interval (in milliseconds) between ping comments sent after the last event.
         *
         * @default 15000
         */
        interval: 15000,
        /**
         * The content of the ping comment. Must not include newline characters.
         *
         * @default ''
         */
        comment: '',
      },
    },
  },
})

Last updated on

Was this page helpful?