Skip to content

Commit

Permalink
feat(parser): enhance API Gateway schemas (#2665)
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamorosi authored Jun 26, 2024
1 parent 5634566 commit b3bc1f0
Show file tree
Hide file tree
Showing 29 changed files with 1,958 additions and 362 deletions.
3 changes: 3 additions & 0 deletions docs/utilities/parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ Parser comes with the following built-in schemas:
| -------------------------------------------- | ------------------------------------------------------------------------------------- |
| **AlbSchema** | Lambda Event Source payload for Amazon Application Load Balancer |
| **APIGatewayProxyEventSchema** | Lambda Event Source payload for Amazon API Gateway |
| **APIGatewayRequestAuthorizerEventSchema** | Lambda Event Source payload for Amazon API Gateway Request Authorizer |
| **APIGatewayTokenAuthorizerEventSchema** | Lambda Event Source payload for Amazon API Gateway Token Authorizer |
| **APIGatewayProxyEventV2Schema** | Lambda Event Source payload for Amazon API Gateway v2 payload |
| **APIGatewayRequestAuthorizerEventV2Schema** | Lambda Event Source payload for Amazon API Gateway v2 Authorizer |
| **CloudFormationCustomResourceCreateSchema** | Lambda Event Source payload for AWS CloudFormation `CREATE` operation |
| **CloudFormationCustomResourceUpdateSchema** | Lambda Event Source payload for AWS CloudFormation `UPDATE` operation |
| **CloudFormationCustomResourceDeleteSchema** | Lambda Event Source payload for AWS CloudFormation `DELETE` operation |
Expand Down
3 changes: 1 addition & 2 deletions packages/parser/jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ module.exports = {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
transform: {
'^.+\\.ts?$': ['ts-jest', {tsconfig: './tests/tsconfig.json'}],

'^.+\\.ts?$': ['ts-jest'],
},
moduleFileExtensions: ['js', 'ts'],
collectCoverageFrom: ['**/src/**/*.ts', '!**/node_modules/**'],
Expand Down
16 changes: 16 additions & 0 deletions packages/parser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
"require": "./lib/cjs/schemas/index.js",
"import": "./lib/esm/schemas/index.js"
},
"./schemas/api-gateway": {
"require": "./lib/cjs/schemas/apigw.js",
"import": "./lib/esm/schemas/apigw.js"
},
"./schemas/api-gatewayv2": {
"require": "./lib/cjs/schemas/apigwv2.js",
"import": "./lib/esm/schemas/apigwv2.js"
},
"./envelopes": {
"require": "./lib/cjs/envelopes/index.js",
"import": "./lib/esm/envelopes/index.js"
Expand All @@ -66,6 +74,14 @@
"./lib/cjs/schemas/index.d.ts",
"./lib/esm/schemas/index.d.ts"
],
"schemas/api-gateway": [
"./lib/cjs/schemas/apigw.d.ts",
"./lib/esm/schemas/apigw.d.ts"
],
"schemas/api-gatewayv2": [
"./lib/cjs/schemas/apigwv2.d.ts",
"./lib/esm/schemas/apigwv2.d.ts"
],
"envelopes": [
"./lib/cjs/envelopes/index.d.ts",
"./lib/esm/envelopes/index.d.ts"
Expand Down
45 changes: 45 additions & 0 deletions packages/parser/src/schemas/apigw-proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { z } from 'zod';

/**
* A zod schema for an API Gateway Certificate
*/
const APIGatewayCert = z.object({
clientCertPem: z.string(),
subjectDN: z.string(),
issuerDN: z.string(),
serialNumber: z.string(),
validity: z.object({
notBefore: z.string(),
notAfter: z.string(),
}),
});

/**
* A zod schema for an object with string keys and string values
*/
const APIGatewayRecord = z.record(z.string());

/**
* A zod schema for an array of strings
*/
const APIGatewayStringArray = z.array(z.string());

/**
* A zod schema for API Gateway HTTP methods
*/
const APIGatewayHttpMethod = z.enum([
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'HEAD',
'OPTIONS',
]);

export {
APIGatewayCert,
APIGatewayRecord,
APIGatewayStringArray,
APIGatewayHttpMethod,
};
219 changes: 182 additions & 37 deletions packages/parser/src/schemas/apigw.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { z } from 'zod';
import {
APIGatewayCert,
APIGatewayRecord,
APIGatewayStringArray,
APIGatewayHttpMethod,
} from './apigw-proxy.js';

const APIGatewayCert = z.object({
clientCertPem: z.string(),
subjectDN: z.string(),
issuerDN: z.string(),
serialNumber: z.string(),
validity: z.object({
notBefore: z.string(),
notAfter: z.string(),
}),
});

/**
* A zod schema for an API Gateway Event Identity
*
* @see {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html}
*/
const APIGatewayEventIdentity = z.object({
accessKey: z.string().nullish(),
accountId: z.string().nullish(),
Expand Down Expand Up @@ -38,15 +38,27 @@ const APIGatewayEventIdentity = z.object({
clientCert: APIGatewayCert.nullish(),
});

/**
* A zod schema for an API Gateway Event Request Context
*
* @see {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference}
*/
const APIGatewayEventRequestContext = z
.object({
accountId: z.string(),
apiId: z.string(),
deploymentId: z.string().nullish(),
authorizer: z
.object({
claims: z.record(z.string(), z.any()).nullish(),
scopes: z.array(z.string()).nullish(),
})
.union([
z.object({
integrationLatency: z.number(),
principalId: z.string(),
}),
z.object({
claims: z.record(z.string(), z.any()),
scopes: APIGatewayStringArray.optional(),
}),
])
.nullish(),
stage: z.string(),
protocol: z.string(),
Expand Down Expand Up @@ -88,32 +100,165 @@ const APIGatewayEventRequestContext = z
}
);

/**
* A zod schema for an API Gateway Proxy event
*
* @example
* ```json
* {
* "type": "REQUEST",
* "methodArn": "arn:aws:execute-api:us-east-1:123456789012:abcdef123/test/GET/request",
* "resource": "/request",
* "path": "/request",
* "httpMethod": "GET",
* "headers": {
* "X-AMZ-Date": "20170718T062915Z",
* "Accept": "application/json",
* "HeaderAuth1": "headerValue1"
* },
* "queryStringParameters": {
* "QueryString1": "queryValue1"
* },
* "pathParameters": {},
* "stageVariables": null,
* "requestContext": {
* "path": "/request",
* "accountId": "123456789012",
* "resourceId": "05c7jb",
* "stage": "test",
* "requestId": "...",
* "identity": {
* "cognitoIdentityPoolId": null,
* "accountId": null,
* "cognitoIdentityId": null,
* "caller": null,
* "sourceIp": "192.168.1.1",
* "principalOrgId": null,
* "accessKey": null,
* "cognitoAuthenticationType": null,
* "cognitoAuthenticationProvider": null,
* "userArn": null,
* "userAgent": "HTTPie/3.2.2",
* "user": null
* }
* },
* "resourcePath": "/request",
* "httpMethod": "GET",
* "apiId": "abcdef123"
* }
* ```
*
* @see {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html}
*/
const APIGatewayProxyEventSchema = z.object({
version: z.string().optional(),
authorizationToken: z.string().optional(),
identitySource: z.string().optional(),
methodArn: z.string().optional(),
type: z.enum(['TOKEN', 'REQUEST']).optional(),
resource: z.string(),
path: z.string(),
httpMethod: z.enum([
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'HEAD',
'OPTIONS',
]),
headers: z.record(z.string()).optional(),
queryStringParameters: z.record(z.string()).nullable(),
multiValueHeaders: z.record(z.array(z.string())).optional(),
multiValueQueryStringParameters: z.record(z.array(z.string())).nullable(),
httpMethod: APIGatewayHttpMethod,
headers: APIGatewayRecord.nullish(),
multiValueHeaders: z.record(APIGatewayStringArray).nullish(),
queryStringParameters: APIGatewayRecord.nullable(),
multiValueQueryStringParameters: z.record(APIGatewayStringArray).nullable(),
pathParameters: APIGatewayRecord.nullish(),
stageVariables: APIGatewayRecord.nullish(),
requestContext: APIGatewayEventRequestContext,
pathParameters: z.record(z.string()).optional().nullish(),
stageVariables: z.record(z.string()).optional().nullish(),
isBase64Encoded: z.boolean().optional(),
body: z.string().nullable(),
isBase64Encoded: z.boolean(),
});

/**
* A zod schema for an API Gateway Request Authorizer event
*
* @example
* ```json
* {
* "type": "REQUEST",
* "methodArn": "arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/prod/GET/",
* "resource": "/{proxy+}",
* "path": "/hello/world",
* "httpMethod": "GET",
* "headers": {
* "X-AMZ-Date": "20170718T062915Z",
* "Accept": "application/json",
* "HeaderAuth1": "headerValue1"
* },
* "multiValueHeaders": {
* "X-AMZ-Date": ["20170718T062915Z"],
* "Accept": ["application/json"],
* "HeaderAuth1": ["headerValue1"]
* },
* "queryStringParameters": {},
* "multiValueQueryStringParameters": {},
* "pathParameters": {},
* "stageVariables": {},
* "requestContext": {
* "path": "/request",
* "accountId": "123456789012",
* "resourceId": "05c7jb",
* "stage": "test",
* "requestId": "...",
* "identity": {
* "cognitoIdentityPoolId": null,
* "accountId": null,
* "cognitoIdentityId": null,
* "caller": null,
* "sourceIp": "192.168.1.1",
* "principalOrgId": null,
* "accessKey": null,
* "cognitoAuthenticationType": null,
* "cognitoAuthenticationProvider": null,
* "userArn": null,
* "userAgent": "HTTPie/3.2.2",
* "user": null
* }
* },
* "domainName": "id.execute-api.us-west-2.amazonaws.com",
* "deploymentId": "lle82z",
* "apiId": "ymy8tbxw7b"
* }
* ```
*
* @see {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-input.html#w76aac15b9c21c25c21b5}
*/
const APIGatewayRequestAuthorizerEventSchema = z.object({
type: z.literal('REQUEST'),
methodArn: z.string(),
resource: z.string(),
path: z.string(),
httpMethod: APIGatewayHttpMethod,
headers: APIGatewayRecord,
multiValueHeaders: z.record(APIGatewayStringArray),
queryStringParameters: APIGatewayRecord,
multiValueQueryStringParameters: z.record(APIGatewayStringArray),
pathParameters: APIGatewayRecord,
stageVariables: APIGatewayRecord,
requestContext: APIGatewayEventRequestContext,
domainName: z.string().optional(),
deploymentId: z.string().optional(),
apiId: z.string().optional(),
});

/**
* A zod schema for an API Gateway Token Authorizer event
*
* @example
* ```json
* {
* "type": "TOKEN",
* "authorizationToken": "Bearer abcd1234",
* "methodArn": "arn:aws:execute-api:us-west-2:123456789012:ymy8tbxw7b/prod/GET/"
* }
* ```
*
* @see {@link https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-input.html#w76aac15b9c21c25c21b3}
*/
const APIGatewayTokenAuthorizerEventSchema = z.object({
type: z.literal('TOKEN'),
authorizationToken: z.string(),
methodArn: z.string(),
});

export { APIGatewayProxyEventSchema, APIGatewayCert };
export {
APIGatewayProxyEventSchema,
APIGatewayRequestAuthorizerEventSchema,
APIGatewayTokenAuthorizerEventSchema,
};
Loading

0 comments on commit b3bc1f0

Please sign in to comment.