mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nitro): add support for lambda v2 payload format (#3070)
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
parent
68a227af03
commit
614e87e9f0
@ -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.
|
||||
@ -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: '/' })
|
||||
```
|
||||
|
@ -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",
|
||||
|
@ -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]))
|
||||
}
|
||||
|
@ -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 || ''
|
||||
}
|
||||
|
@ -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
|
||||
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user