Skip to content

Commit fae3cd1

Browse files
committed
pathConfig type, RestApiConstructProps restructure, add iteration for each path, and modify test object
1 parent 6464351 commit fae3cd1

File tree

3 files changed

+80
-56
lines changed

3 files changed

+80
-56
lines changed
Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,39 @@
11
import { describe, it } from 'node:test';
2-
import { AmplifyConstruct } from './construct.js';
2+
import { RestApiConstruct } from './construct.js';
33
import { App, Stack } from 'aws-cdk-lib';
44
import { Template } from 'aws-cdk-lib/assertions';
5+
import * as lambda from 'aws-cdk-lib/aws-lambda';
56

6-
void describe('AmplifyConstruct', () => {
7+
void describe('RestApiConstruct', () => {
78
void it('creates a queue if specified', () => {
89
const app = new App();
910
const stack = new Stack(app);
10-
new AmplifyConstruct(stack, 'test', {
11-
includeQueue: true,
11+
new RestApiConstruct(stack, 'RestApiTest', {
12+
apiName: 'RestApiTest',
13+
apiProps: [
14+
{
15+
path: '/test',
16+
routes: ['GET', 'POST'],
17+
lambdaEntry: {
18+
runtime: lambda.Runtime.NODEJS_18_X,
19+
source: {
20+
path: './test-lambda',
21+
},
22+
},
23+
},
24+
{
25+
path: '/blog',
26+
routes: ['GET', 'POST', 'PUT'],
27+
lambdaEntry: {
28+
runtime: lambda.Runtime.NODEJS_18_X,
29+
source: {
30+
path: './blog-lambda',
31+
},
32+
},
33+
},
34+
],
1235
});
1336
const template = Template.fromStack(stack);
14-
template.resourceCountIs('AWS::SQS::Queue', 1);
15-
});
16-
17-
void it('does nothing if queue is false', () => {
18-
const app = new App();
19-
const stack = new Stack(app);
20-
new AmplifyConstruct(stack, 'test', {
21-
includeQueue: false,
22-
});
23-
const template = Template.fromStack(stack);
24-
template.resourceCountIs('AWS::SQS::Queue', 0);
37+
template.resourceCountIs('AWS::AGW::RestApi', 1);
2538
});
2639
});

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

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,83 @@
11
import { Construct } from 'constructs';
22
import * as lambda from 'aws-cdk-lib/aws-lambda';
3-
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
3+
import * as apiGateway from 'aws-cdk-lib/aws-apigateway';
44
import {
55
ExistingDirectory,
66
ExistingLambda,
77
NewFromCode,
8-
NewFromTemplate,
8+
// NewFromTemplate,
99
RestApiConstructProps,
1010
} from './types.js';
1111

1212
/**
1313
* Rest API construct for Amplify Backend
1414
*/
1515
export class RestApiConstruct extends Construct {
16-
public readonly api: apigateway.RestApi;
16+
public readonly api: apiGateway.RestApi;
1717
/**
1818
* Create a new RestApiConstruct
1919
*/
2020
constructor(scope: Construct, id: string, props: RestApiConstructProps) {
2121
super(scope, id);
2222

23-
let code: lambda.AssetCode | lambda.InlineCode = lambda.Code.fromInline('');
24-
const src = props.lambdaEntry.source;
25-
if ('path' in src) {
26-
const lamb = src as ExistingDirectory;
27-
code = lambda.Code.fromAsset(lamb.path);
28-
} else if ('code' in src) {
29-
const lamb = src as NewFromCode;
30-
code = lambda.Code.fromInline(lamb.code);
31-
} else if ('template' in src) {
32-
//TODO: Implement use of templates (which ones to support, and how - cli version is complex). The available templates depend on the runtime
33-
const lamb = src as NewFromTemplate;
34-
if (lamb.template === 'Hello World') {
35-
code = lambda.Code.fromInline(
36-
"function handler() {console.log('Hello World!');}",
37-
);
38-
}
39-
}
40-
41-
let handler: lambda.IFunction;
42-
if ('id' in src) {
43-
const lamb = src as ExistingLambda;
44-
handler = lambda.Function.fromFunctionName(this, lamb.id, lamb.name);
45-
} else {
46-
handler = new lambda.Function(this, 'handler', {
47-
runtime: props.lambdaEntry.runtime,
48-
handler: 'index.handler',
49-
code: code,
50-
});
51-
}
52-
5323
// Create a new API Gateway REST API with the specified name
54-
this.api = new apigateway.RestApi(this, 'RestApi', {
24+
this.api = new apiGateway.RestApi(this, 'RestApi', {
5525
restApiName: props.apiName,
5626
});
5727

58-
// Create a resource for the specified path
59-
const resource = this.addNestedResource(this.api.root, props.path);
28+
// Iterate over each path configuration
29+
for (const [index, pathConfig] of Object.entries(props.apiProps)) {
30+
const { path, routes, lambdaEntry } = pathConfig;
31+
const source = lambdaEntry.source;
6032

61-
// Add methods to the resource for each HTTP method specified in props.routes
62-
for (const method of props.routes) {
63-
resource.addMethod(method, new apigateway.LambdaIntegration(handler));
33+
// Determine Lambda code source
34+
let code: lambda.AssetCode | lambda.InlineCode =
35+
lambda.Code.fromInline('');
36+
if ('path' in source) {
37+
const src = source as ExistingDirectory;
38+
code = lambda.Code.fromAsset(src.path);
39+
} else if ('code' in source) {
40+
const src = source as NewFromCode;
41+
code = lambda.Code.fromInline(src.code);
42+
} else if ('template' in source) {
43+
// const src = source as NewFromTemplate;
44+
// NOTE: You may expand supported templates later
45+
code = lambda.Code.fromInline(
46+
"exports.handler = () => { console.log('Hello World'); };",
47+
);
48+
} else {
49+
// fallback to dummy if none matched — should never happen if typing is correct
50+
code = lambda.Code.fromInline('exports.handler = () => {};');
51+
}
52+
53+
// Create or reference Lambda function
54+
let handler: lambda.IFunction;
55+
if ('id' in source) {
56+
const src = source as ExistingLambda;
57+
handler = lambda.Function.fromFunctionName(this, src.id, src.name);
58+
} else {
59+
handler = new lambda.Function(this, `LambdaHandler-${index}`, {
60+
runtime: lambdaEntry.runtime,
61+
handler: 'index.handler',
62+
code,
63+
});
64+
}
65+
66+
// Add resource and methods for this route
67+
const resource = this.addNestedResource(this.api.root, path);
68+
for (const method of routes) {
69+
resource.addMethod(method, new apiGateway.LambdaIntegration(handler));
70+
}
6471
}
6572
}
6673

6774
/**
6875
* Adds nested resources to the API based on the provided path.
6976
*/
7077
private addNestedResource(
71-
root: apigateway.IResource,
78+
root: apiGateway.IResource,
7279
path: string,
73-
): apigateway.IResource {
80+
): apiGateway.IResource {
7481
return path.split('/').reduce((resource, part) => {
7582
return resource.getResource(part) ?? resource.addResource(part);
7683
}, root);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ type LambdaSource = {
1414

1515
export type RestApiConstructProps = {
1616
apiName: string;
17+
apiProps: RestApiPathConfig[];
18+
};
19+
20+
export type RestApiPathConfig = {
1721
path: string;
1822
routes: HttpMethod[];
1923
lambdaEntry: LambdaSource;

0 commit comments

Comments
 (0)