Skip to content

Commit 6fb6d5f

Browse files
committed
feature(function): add custom runtimes to defineFunction
1 parent 15bf421 commit 6fb6d5f

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

packages/backend-function/src/factory.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { NodeVersion, defineFunction } from './factory.js';
1717
import { lambdaWithDependencies } from './test-assets/lambda-with-dependencies/resource.js';
1818
import { Runtime } from 'aws-cdk-lib/aws-lambda';
1919
import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam';
20+
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
2021

2122
const createStackAndSetContext = (): Stack => {
2223
const app = new App();
@@ -282,6 +283,20 @@ void describe('AmplifyFunctionFactory', () => {
282283
});
283284
});
284285

286+
void it('sets valid custom lambda function runtime', () => {
287+
const lambda = defineFunction((scope) => {
288+
return new NodejsFunction(scope, 'customFunction', {
289+
entry:
290+
'./packages/backend-function/src/test-assets/default-lambda/handler.ts',
291+
});
292+
}).getInstance(getInstanceProps);
293+
const template = Template.fromStack(Stack.of(lambda.resources.lambda));
294+
295+
template.hasResourceProperties('AWS::Lambda::Function', {
296+
Runtime: Runtime.NODEJS_16_X.name,
297+
});
298+
});
299+
285300
void it('defaults to oldest LTS runtime', () => {
286301
const lambda = defineFunction({
287302
entry: './test-assets/default-lambda/handler.ts',
@@ -413,6 +428,7 @@ void describe('AmplifyFunctionFactory', () => {
413428
entry: './test-assets/default-lambda/handler.ts',
414429
name: 'anotherName',
415430
});
431+
416432
const functionStack = Stack.of(
417433
functionFactory.getInstance(getInstanceProps).resources.lambda
418434
);

packages/backend-function/src/factory.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,25 @@ import { FunctionEnvironmentTypeGenerator } from './function_env_type_generator.
3131
import { AttributionMetadataStorage } from '@aws-amplify/backend-output-storage';
3232
import { fileURLToPath } from 'node:url';
3333
import { AmplifyUserError, TagName } from '@aws-amplify/platform-core';
34+
import * as lambda from 'aws-cdk-lib/aws-lambda';
3435

3536
const functionStackType = 'function-Lambda';
3637

3738
/**
3839
* Entry point for defining a function in the Amplify ecosystem
3940
*/
4041
export const defineFunction = (
41-
props: FunctionProps = {}
42+
props?: FunctionProps | ((scope: Construct) => lambda.Function)
4243
): ConstructFactory<
4344
ResourceProvider<FunctionResources> & ResourceAccessAcceptorFactory
44-
> => new FunctionFactory(props, new Error().stack);
45+
> => {
46+
if (props === undefined || props === null) {
47+
return new FunctionFactory({}, new Error().stack);
48+
} else if (typeof props === 'function') {
49+
return new FunctionFactory({}, new Error().stack, props);
50+
}
51+
return new FunctionFactory(props, new Error().stack);
52+
};
4553

4654
export type FunctionProps = {
4755
/**
@@ -99,7 +107,8 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
99107
*/
100108
constructor(
101109
private readonly props: FunctionProps,
102-
private readonly callerStack?: string
110+
private readonly callerStack?: string,
111+
private readonly callback?: (scope: Construct) => lambda.Function
103112
) {}
104113

105114
/**
@@ -113,7 +122,8 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
113122
if (!this.generator) {
114123
this.generator = new FunctionGenerator(
115124
this.hydrateDefaults(resourceNameValidator),
116-
outputStorageStrategy
125+
outputStorageStrategy,
126+
this.callback as (scope: Construct) => lambda.Function
117127
);
118128
}
119129
return constructContainer.getOrCompute(this.generator) as AmplifyFunction;
@@ -229,7 +239,8 @@ class FunctionGenerator implements ConstructContainerEntryGenerator {
229239

230240
constructor(
231241
private readonly props: HydratedFunctionProps,
232-
private readonly outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
242+
private readonly outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>,
243+
private readonly callback: (scope: Construct) => lambda.Function
233244
) {}
234245

235246
generateContainerEntry = ({
@@ -241,7 +252,8 @@ class FunctionGenerator implements ConstructContainerEntryGenerator {
241252
this.props.name,
242253
this.props,
243254
backendSecretResolver,
244-
this.outputStorageStrategy
255+
this.outputStorageStrategy,
256+
this.callback
245257
);
246258
};
247259
}
@@ -257,7 +269,8 @@ class AmplifyFunction
257269
id: string,
258270
props: HydratedFunctionProps,
259271
backendSecretResolver: BackendSecretResolver,
260-
outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
272+
outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>,
273+
callback: (scope: Construct) => lambda.Function
261274
) {
262275
super(scope, id);
263276

@@ -298,20 +311,24 @@ class AmplifyFunction
298311

299312
let functionLambda;
300313
try {
301-
functionLambda = new NodejsFunction(scope, `${id}-lambda`, {
302-
entry: props.entry,
303-
timeout: Duration.seconds(props.timeoutSeconds),
304-
memorySize: props.memoryMB,
305-
runtime: nodeVersionMap[props.runtime],
306-
bundling: {
307-
format: OutputFormat.ESM,
308-
banner: bannerCode,
309-
inject: shims,
310-
loader: {
311-
'.node': 'file',
314+
if (callback != null) {
315+
functionLambda = callback(scope);
316+
} else {
317+
functionLambda = new NodejsFunction(scope, `${id}-lambda`, {
318+
entry: props.entry,
319+
timeout: Duration.seconds(props.timeoutSeconds),
320+
memorySize: props.memoryMB,
321+
runtime: nodeVersionMap[props.runtime],
322+
bundling: {
323+
format: OutputFormat.ESM,
324+
banner: bannerCode,
325+
inject: shims,
326+
loader: {
327+
'.node': 'file',
328+
},
312329
},
313-
},
314-
});
330+
});
331+
}
315332
} catch (error) {
316333
throw new AmplifyUserError(
317334
'NodeJSFunctionConstructInitializationError',

0 commit comments

Comments
 (0)