Skip to content

Commit 7a293a3

Browse files
authored
Merge pull request #8 from bennettsf/lambda-change-resource-provider
Lambda change to use ResourceProvider
2 parents e16ea47 + a68d44d commit 7a293a3

File tree

10 files changed

+136
-166
lines changed

10 files changed

+136
-166
lines changed

package-lock.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/rest-api-construct/API.md

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,25 @@
66

77
import * as apiGateway from 'aws-cdk-lib/aws-apigateway';
88
import { Construct } from 'constructs';
9-
import * as lamb from 'aws-cdk-lib/aws-lambda';
9+
import { IFunction } from 'aws-cdk-lib/aws-lambda';
1010

1111
// @public (undocumented)
12-
export type ExistingDirectory = {
13-
path: string;
14-
};
15-
16-
// @public (undocumented)
17-
export type ExistingLambda = {
18-
id: string;
19-
name: string;
12+
export type AuthorizerConfig = {
13+
type: 'none';
14+
} | {
15+
type: 'userPool';
16+
} | {
17+
type: 'userPool';
18+
groups: string[];
2019
};
2120

2221
// @public (undocumented)
2322
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS';
2423

2524
// @public (undocumented)
26-
export type LambdaSource = {
27-
runtime: lamb.Runtime;
28-
source: ExistingDirectory | ExistingLambda | NewFromCode;
29-
};
30-
31-
// @public (undocumented)
32-
export type NewFromCode = {
33-
code: string;
25+
export type MethodsProps = {
26+
method: HttpMethod;
27+
authorizer?: AuthorizerConfig;
3428
};
3529

3630
// @public
@@ -49,8 +43,8 @@ export type RestApiConstructProps = {
4943
// @public (undocumented)
5044
export type RestApiPathConfig = {
5145
path: string;
52-
routes: HttpMethod[];
53-
lambdaEntry: LambdaSource;
46+
methods: MethodsProps[];
47+
lambdaEntry: IFunction;
5448
};
5549

5650
// (No @packageDocumentation comment for this package)

packages/rest-api-construct/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,9 @@
2121
"peerDependencies": {
2222
"aws-cdk-lib": "^2.189.0",
2323
"constructs": "^10.0.0"
24+
},
25+
"dependencies": {
26+
"@aws-amplify/backend": "^1.16.1",
27+
"@aws-amplify/backend-output-storage": "^1.3.1"
2428
}
2529
}
Lines changed: 79 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,104 @@
11
import { describe, it } from 'node:test';
22
import { RestApiConstruct } from './construct.js';
33
import { App, Stack } from 'aws-cdk-lib';
4-
import { Template } from 'aws-cdk-lib/assertions';
5-
import * as lambda from 'aws-cdk-lib/aws-lambda';
4+
import { defineFunction } from '@aws-amplify/backend';
5+
import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage';
6+
import {
7+
ConstructContainerStub,
8+
ResourceNameValidatorStub,
9+
StackResolverStub,
10+
} from '@aws-amplify/backend-platform-test-stubs';
11+
import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types';
612

713
void describe('RestApiConstruct Lambda Handling', () => {
8-
void it('loads an existing local lambda function if the directory is specified', () => {
14+
void it('integrates the result of defineFunction into the api', () => {
915
const app = new App();
1016
const stack = new Stack(app);
11-
new RestApiConstruct(stack, 'RestApiLambdaTest', {
12-
apiName: 'RestApiLambdaTest',
13-
apiProps: [
14-
{
15-
path: 'items',
16-
defaultAuthorizer: { type: 'none' },
17-
methods: [
18-
{
19-
method: 'GET',
20-
authorizer: { type: 'none' },
21-
},
22-
],
23-
lambdaEntry: {
24-
runtime: lambda.Runtime.NODEJS_18_X,
25-
source: { path: 'packages/rest-api-construct/lib/test-assets' },
26-
},
27-
},
28-
],
29-
});
30-
const template = Template.fromStack(stack);
31-
template.hasResourceProperties('AWS::Lambda::Function', {
32-
Handler: 'index.handler',
17+
const factory = defineFunction({
18+
name: 'Test Function',
19+
entry: './test-assets/handler.ts',
3320
});
34-
});
3521

36-
void it('creates a new lambda function if the code is specified', () => {
37-
const app = new App();
38-
const stack = new Stack(app);
39-
new RestApiConstruct(stack, 'RestApiNewLambdaTest', {
40-
apiName: 'RestApiNewLambda',
41-
apiProps: [
42-
{
43-
path: 'items',
44-
defaultAuthorizer: { type: 'none' },
45-
methods: [
46-
{
47-
method: 'GET',
48-
authorizer: { type: 'none' },
49-
},
50-
],
51-
lambdaEntry: {
52-
runtime: lambda.Runtime.NODEJS_22_X,
53-
source: {
54-
code: "export const handler = () => {return 'Hello World! This is a new lambda function.';};",
55-
},
56-
},
57-
},
58-
],
59-
});
60-
const template = Template.fromStack(stack);
61-
template.hasResourceProperties('AWS::Lambda::Function', {
62-
Handler: 'index.handler',
63-
});
64-
});
65-
});
22+
//stubs for the instance props
23+
const constructContainer = new ConstructContainerStub(
24+
new StackResolverStub(stack),
25+
);
26+
const outputStorageStrategy = new StackMetadataBackendOutputStorageStrategy(
27+
stack,
28+
);
29+
const resourceNameValidator = new ResourceNameValidatorStub();
30+
const getInstanceProps: ConstructFactoryGetInstanceProps = {
31+
constructContainer,
32+
outputStorageStrategy,
33+
resourceNameValidator,
34+
};
35+
36+
const resource = factory.getInstance(getInstanceProps);
6637

67-
void describe('RestApiConstruct', () => {
68-
void it('creates a queue if specified', () => {
69-
const app = new App();
70-
const stack = new Stack(app);
7138
new RestApiConstruct(stack, 'RestApiTest', {
7239
apiName: 'RestApiTest',
7340
apiProps: [
7441
{
75-
path: '/test',
42+
path: 'items',
43+
lambdaEntry: resource,
7644
methods: [
7745
{
7846
method: 'GET',
7947
authorizer: { type: 'none' },
8048
},
8149
],
82-
lambdaEntry: {
83-
runtime: lambda.Runtime.NODEJS_18_X,
84-
source: {
85-
path: './test-lambda',
86-
},
87-
},
88-
},
89-
{
90-
path: '/blog',
91-
methods: [
92-
{
93-
method: 'POST',
94-
authorizer: { type: 'userPool', groups: ['Admins'] },
95-
},
96-
{
97-
method: 'GET',
98-
authorizer: { type: 'userPool' },
99-
},
100-
],
101-
defaultAuthorizer: { type: 'userPool' },
102-
lambdaEntry: {
103-
runtime: lambda.Runtime.NODEJS_18_X,
104-
source: {
105-
path: './blog-lambda',
106-
},
107-
},
10850
},
10951
],
11052
});
111-
const template = Template.fromStack(stack);
112-
template.resourceCountIs('AWS::AGW::RestApi', 1);
11353
});
11454
});
55+
56+
//test needs to be updated to new lambda handling
57+
// void describe('RestApiConstruct', () => {
58+
// void it('creates a queue if specified', () => {
59+
// const app = new App();
60+
// const stack = new Stack(app);
61+
// new RestApiConstruct(stack, 'RestApiTest', {
62+
// apiName: 'RestApiTest',
63+
// apiProps: [
64+
// {
65+
// path: '/test',
66+
// methods: [
67+
// {
68+
// method: 'GET',
69+
// authorizer: { type: 'none' },
70+
// },
71+
// ],
72+
// lambdaEntry: {
73+
// runtime: lambda.Runtime.NODEJS_18_X,
74+
// source: {
75+
// path: './test-lambda',
76+
// },
77+
// },
78+
// },
79+
// {
80+
// path: '/blog',
81+
// methods: [
82+
// {
83+
// method: 'POST',
84+
// authorizer: { type: 'userPool', groups: ['Admins'] },
85+
// },
86+
// {
87+
// method: 'GET',
88+
// authorizer: { type: 'userPool' },
89+
// },
90+
// ],
91+
// defaultAuthorizer: { type: 'userPool' },
92+
// lambdaEntry: {
93+
// runtime: lambda.Runtime.NODEJS_18_X,
94+
// source: {
95+
// path: './blog-lambda',
96+
// },
97+
// },
98+
// },
99+
// ],
100+
// });
101+
// const template = Template.fromStack(stack);
102+
// template.resourceCountIs('AWS::AGW::RestApi', 1);
103+
// });
104+
// });

packages/rest-api-construct/src/construct.ts

Lines changed: 5 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import { Construct } from 'constructs';
2-
import * as lambda from 'aws-cdk-lib/aws-lambda';
32
import * as apiGateway from 'aws-cdk-lib/aws-apigateway';
4-
import {
5-
ExistingDirectory,
6-
ExistingLambda,
7-
NewFromCode,
8-
RestApiConstructProps,
9-
} from './types.js';
3+
import { RestApiConstructProps } from './types.js';
104

115
/**
126
* Rest API construct for Amplify Backend
@@ -25,40 +19,14 @@ export class RestApiConstruct extends Construct {
2519
});
2620

2721
// Iterate over each path configuration
28-
for (const [index, pathConfig] of Object.entries(props.apiProps)) {
29-
const { path, methods, lambdaEntry } = pathConfig;
30-
const source = lambdaEntry.source;
31-
32-
// Determine Lambda code source - either ExistingDirectory, NewFromCode, or ExistingLambda (function already exists in aws and does not need to be constructed)
33-
let code!: lambda.AssetCode | lambda.InlineCode;
34-
if ('path' in source) {
35-
const src = source as ExistingDirectory;
36-
code = lambda.Code.fromAsset(src.path);
37-
} else if ('code' in source) {
38-
const src = source as NewFromCode;
39-
code = lambda.Code.fromInline(src.code);
40-
}
41-
//if none of these are true, it's a ExistingLambda type, handled below
42-
43-
// Create or reference Lambda function
44-
let handler: lambda.IFunction;
45-
if ('id' in source) {
46-
const src = source as ExistingLambda;
47-
handler = lambda.Function.fromFunctionName(this, src.id, src.name);
48-
} else {
49-
handler = new lambda.Function(this, `LambdaHandler-${index}`, {
50-
runtime: lambdaEntry.runtime,
51-
handler: 'index.handler',
52-
code: code,
53-
});
54-
}
55-
22+
for (const pathConfig of Object.entries(props.apiProps)) {
23+
const { path, methods, lambdaEntry } = pathConfig[1];
5624
// Add resource and methods for this route
5725
const resource = this.addNestedResource(this.api.root, path);
5826
for (const method of methods) {
5927
resource.addMethod(
6028
method.method,
61-
new apiGateway.LambdaIntegration(handler),
29+
new apiGateway.LambdaIntegration(lambdaEntry.resources.lambda),
6230
);
6331
}
6432
}
@@ -71,6 +39,7 @@ export class RestApiConstruct extends Construct {
7139
root: apiGateway.IResource,
7240
path: string,
7341
): apiGateway.IResource {
42+
//TODO: remove leading/trailing slashes from path and check it is not an empty string? eg /items, items/stuff/, /
7443
// Split the path into parts (e.g. "posts/comments" → ["posts", "comments"])
7544
const parts = path.split('/');
7645

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from './construct.js';
22
export * from './types.js';
3-
export { RestApiPathConfig, LambdaSource } from './types.js';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { Handler } from 'aws-lambda';
2+
3+
/**
4+
* Test function
5+
* @returns the string "Hello, World!"
6+
*/
7+
export const handler: Handler = async () => {
8+
return 'Hello, World!';
9+
};

packages/rest-api-construct/src/test-assets/index.ts

Lines changed: 0 additions & 6 deletions
This file was deleted.

0 commit comments

Comments
 (0)