Skip to content
This repository has been archived by the owner on Apr 6, 2023. It is now read-only.

Commit

Permalink
feat(nitro): add support for lambda v2 payload format (#3070)
Browse files Browse the repository at this point in the history
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
  • Loading branch information
danielroe and pi0 committed Feb 7, 2022
1 parent 68a227a commit 614e87e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 8 deletions.
6 changes: 5 additions & 1 deletion docs/content/3.docs/3.deployment/99.presets/lambda.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Or directly use the `NITRO_PRESET` environment variable when running `nuxt build
NITRO_PRESET=lambda npx nuxt build
```

::alert
AWS Lambda [defaults to payload version v2](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html). This Nitro preset supports both v1 and v2 payloads.
::

### Entrypoint

When running `nuxt build` with the Lambda preset, the result will be an entry point that exports a handler function that responds to an event and returns a response.
Expand All @@ -36,5 +40,5 @@ It can be used programmatically or as part of a deployment.
import { handler } from './.output/server'

// Use programmatically
const { statusCode, headers, body } = handler({ path: '/' })
const { statusCode, headers, body } = handler({ rawPath: '/' })
```
1 change: 1 addition & 0 deletions packages/nitro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
},
"devDependencies": {
"@nuxt/schema": "3.0.0",
"@types/aws-lambda": "^8.10.92",
"@types/fs-extra": "^9.0.13",
"@types/http-proxy": "^1.17.8",
"@types/node-fetch": "^3.0.2",
Expand Down
23 changes: 18 additions & 5 deletions packages/nitro/src/runtime/entries/lambda.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
import type { APIGatewayProxyEvent, APIGatewayProxyEventHeaders, APIGatewayProxyEventV2, Context } from 'aws-lambda'
import '#polyfill'
import { withQuery } from 'ufo'
import type { HeadersObject } from 'unenv/runtime/_internal/types'
import { localCall } from '../server'

export async function handler (event, context) {
export const handler = async function handler (event: APIGatewayProxyEvent & APIGatewayProxyEventV2, context: Context) {
const url = withQuery(event.path || event.rawPath, event.queryStringParameters)
const method = event.httpMethod || event.requestContext?.http?.method || 'get'

const r = await localCall({
event,
url: withQuery(event.path, event.queryStringParameters),
url,
context,
headers: event.headers,
method: event.httpMethod,
headers: normalizeIncomingHeaders(event.headers),
method,
query: event.queryStringParameters,
body: event.body // TODO: handle event.isBase64Encoded
})

return {
statusCode: r.status,
headers: r.headers,
headers: normalizeOutgoingHeaders(r.headers),
body: r.body.toString()
}
}

function normalizeIncomingHeaders (headers: APIGatewayProxyEventHeaders) {
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key.toLowerCase(), value as string]))
}

function normalizeOutgoingHeaders (headers: HeadersObject) {
return Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(',') : v]))
}
35 changes: 33 additions & 2 deletions test/presets/lambda.test.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
import { resolve } from 'pathe'
import { describe } from 'vitest'
import type { APIGatewayProxyEvent, APIGatewayProxyEventV2 } from 'aws-lambda'
import { setupTest, testNitroBehavior, importModule } from './_tests'

describe('nitro:preset:lambda', () => {
const ctx = setupTest('lambda')
// Lambda v1 paylod
testNitroBehavior(ctx, async () => {
const { handler } = await importModule(resolve(ctx.outDir, 'server/index.mjs'))
return async ({ url: rawRelativeUrl, headers, method, body }) => {
// creating new URL object to parse query easier
const url = new URL(`https://example.com${rawRelativeUrl}`)
const queryStringParameters = Object.fromEntries(url.searchParams.entries())
const event = {
const event: Partial<APIGatewayProxyEvent> = {
resource: '/my/path',
path: url.pathname,
headers: headers || {},
method: method || 'GET',
httpMethod: method || 'GET',
queryStringParameters,
body: body || ''
}
const res = await handler(event)
return {
data: res.body
}
}
})
// Lambda v2 paylod
testNitroBehavior(ctx, async () => {
const { handler } = await importModule(resolve(ctx.outDir, 'server/index.mjs'))
return async ({ url: rawRelativeUrl, headers, method, body }) => {
// creating new URL object to parse query easier
const url = new URL(`https://example.com${rawRelativeUrl}`)
const queryStringParameters = Object.fromEntries(url.searchParams.entries())
const event: Partial<APIGatewayProxyEventV2> = {
rawPath: url.pathname,
headers: headers || {},
requestContext: {
...Object.fromEntries([['accountId'], ['apiId'], ['domainName'], ['domainPrefix']]),
http: {
path: url.pathname,
protocol: 'http',
...Object.fromEntries([['userAgent'], ['sourceIp']]),
method: method || 'GET'
}
},
queryStringParameters,
body: body || ''
}
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2967,6 +2967,7 @@ __metadata:
"@rollup/plugin-virtual": ^2.0.3
"@rollup/plugin-wasm": ^5.1.2
"@rollup/pluginutils": ^4.1.2
"@types/aws-lambda": ^8.10.92
"@types/fs-extra": ^9.0.13
"@types/http-proxy": ^1.17.8
"@types/jsdom": ^16.2.14
Expand Down Expand Up @@ -3902,6 +3903,13 @@ __metadata:
languageName: node
linkType: hard

"@types/aws-lambda@npm:^8.10.92":
version: 8.10.92
resolution: "@types/aws-lambda@npm:8.10.92"
checksum: 71c44d83a1c88aa6dbc920baedfb2d100b8843a3d210c695ccaafb30dfb75f04398b0e5368100022acbf75c55d456c61774242f20dd70915fc63d85430cbcf8a
languageName: node
linkType: hard

"@types/babel__core@npm:7.1.14":
version: 7.1.14
resolution: "@types/babel__core@npm:7.1.14"
Expand Down

0 comments on commit 614e87e

Please sign in to comment.