Skip to content

Commit ce9df07

Browse files
authored
feat!: expose API runtime constructs (#167)
Introduce separate constructs for just service lambda runtimes, without the API Gateway. BREAKING CHANGE: This update will change the internal node IDs of the constructs. This will cause the Lambdas and API Gateways to be redeployed when upgrading eoapi-cdk. Being that both services are stateless, this should not cause issues unless a developer has made manual modifications or manual references to the deployed lambdas/api gateways.
1 parent 4697ce8 commit ce9df07

File tree

4 files changed

+452
-305
lines changed

4 files changed

+452
-305
lines changed

lib/lambda-api-gateway/index.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import {
2+
Stack,
3+
aws_apigatewayv2 as apigatewayv2,
4+
aws_apigatewayv2_integrations as apigatewayv2_integrations,
5+
aws_lambda as lambda,
6+
} from "aws-cdk-lib";
7+
import { Construct } from "constructs";
8+
9+
export interface LambdaApiGatewayProps {
10+
/**
11+
* Lambda function to integrate with the API Gateway.
12+
*/
13+
readonly lambdaFunction: lambda.Function;
14+
15+
/**
16+
* Custom Domain Name for the API. If defined, will create the
17+
* domain name and integrate it with the API.
18+
*
19+
* @default - undefined
20+
*/
21+
readonly domainName?: apigatewayv2.IDomainName;
22+
23+
/**
24+
* Name of the API Gateway.
25+
*/
26+
readonly apiName?: string;
27+
}
28+
29+
export class LambdaApiGateway extends Construct {
30+
readonly api: apigatewayv2.HttpApi;
31+
32+
constructor(scope: Construct, id: string, props: LambdaApiGatewayProps) {
33+
super(scope, id);
34+
35+
const {
36+
apiName = `${Stack.of(this).stackName}-${id}`,
37+
domainName,
38+
lambdaFunction,
39+
} = props;
40+
41+
const defaultDomainMapping = domainName ? { domainName } : undefined;
42+
43+
const defaultIntegration =
44+
new apigatewayv2_integrations.HttpLambdaIntegration(
45+
"integration",
46+
lambdaFunction,
47+
domainName
48+
? {
49+
parameterMapping:
50+
new apigatewayv2.ParameterMapping().overwriteHeader(
51+
"host",
52+
apigatewayv2.MappingValue.custom(domainName.name)
53+
),
54+
}
55+
: undefined
56+
);
57+
58+
this.api = new apigatewayv2.HttpApi(this, "api", {
59+
apiName,
60+
defaultDomainMapping,
61+
defaultIntegration: defaultIntegration,
62+
});
63+
}
64+
}

lib/stac-api/index.ts

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import {
2-
Stack,
32
aws_apigatewayv2 as apigatewayv2,
4-
aws_apigatewayv2_integrations as apigatewayv2_integrations,
53
aws_ec2 as ec2,
64
aws_rds as rds,
75
aws_lambda as lambda,
86
aws_secretsmanager as secretsmanager,
9-
CfnOutput,
107
Duration,
118
aws_logs,
9+
CfnOutput,
10+
Stack,
1211
} from "aws-cdk-lib";
1312
import { Construct } from "constructs";
1413
import { CustomLambdaFunctionProps } from "../utils";
14+
import { LambdaApiGateway } from "../lambda-api-gateway";
1515
import * as path from "path";
1616

1717
export const EXTENSIONS = {
@@ -35,11 +35,14 @@ function isValidExtension(value: string): value is ExtensionType {
3535
return Object.values(EXTENSIONS).includes(value as any);
3636
}
3737

38-
export class PgStacApiLambda extends Construct {
39-
readonly url: string;
40-
public stacApiLambdaFunction: lambda.Function;
38+
export class PgStacApiLambdaRuntime extends Construct {
39+
public readonly lambdaFunction: lambda.Function;
4140

42-
constructor(scope: Construct, id: string, props: PgStacApiLambdaProps) {
41+
constructor(
42+
scope: Construct,
43+
id: string,
44+
props: PgStacApiLambdaRuntimeProps
45+
) {
4346
super(scope, id);
4447

4548
const defaultExtensions: ExtensionType[] = [
@@ -66,7 +69,7 @@ export class PgStacApiLambda extends Construct {
6669

6770
const enabledExtensions = props.enabledExtensions || defaultExtensions;
6871

69-
this.stacApiLambdaFunction = new lambda.Function(this, "lambda", {
72+
this.lambdaFunction = new lambda.Function(this, "lambda", {
7073
// defaults
7174
runtime: lambda.Runtime.PYTHON_3_11,
7275
handler: "handler.handler",
@@ -91,53 +94,19 @@ export class PgStacApiLambda extends Construct {
9194
...props.lambdaFunctionOptions,
9295
});
9396

94-
props.dbSecret.grantRead(this.stacApiLambdaFunction);
97+
props.dbSecret.grantRead(this.lambdaFunction);
9598

9699
if (props.vpc) {
97-
this.stacApiLambdaFunction.connections.allowTo(
100+
this.lambdaFunction.connections.allowTo(
98101
props.db,
99102
ec2.Port.tcp(5432),
100103
"allow connections from stac-fastapi-pgstac"
101104
);
102105
}
103-
104-
const stacApi = new apigatewayv2.HttpApi(
105-
this,
106-
`${Stack.of(this).stackName}-stac-api`,
107-
{
108-
defaultDomainMapping: props.stacApiDomainName
109-
? {
110-
domainName: props.stacApiDomainName,
111-
}
112-
: undefined,
113-
defaultIntegration: new apigatewayv2_integrations.HttpLambdaIntegration(
114-
"integration",
115-
this.stacApiLambdaFunction,
116-
props.stacApiDomainName
117-
? {
118-
parameterMapping:
119-
new apigatewayv2.ParameterMapping().overwriteHeader(
120-
"host",
121-
apigatewayv2.MappingValue.custom(
122-
props.stacApiDomainName.name
123-
)
124-
),
125-
}
126-
: undefined
127-
),
128-
}
129-
);
130-
131-
this.url = stacApi.url!;
132-
133-
new CfnOutput(this, "stac-api-output", {
134-
exportName: `${Stack.of(this).stackName}-url`,
135-
value: this.url,
136-
});
137106
}
138107
}
139108

140-
export interface PgStacApiLambdaProps {
109+
export interface PgStacApiLambdaRuntimeProps {
141110
/**
142111
* VPC into which the lambda should be deployed.
143112
*/
@@ -163,15 +132,10 @@ export interface PgStacApiLambdaProps {
163132
*/
164133
readonly apiEnv?: Record<string, string>;
165134

166-
/**
167-
* Custom Domain Name Options for STAC API,
168-
*/
169-
readonly stacApiDomainName?: apigatewayv2.IDomainName;
170-
171135
/**
172136
* List of STAC API extensions to enable.
173137
*
174-
* @default - query, sort, fields, filter, free_text, pagniation, collection_search
138+
* @default - query, sort, fields, filter, free_text, pagination, collection_search
175139
*/
176140
readonly enabledExtensions?: ExtensionType[];
177141

@@ -182,3 +146,64 @@ export interface PgStacApiLambdaProps {
182146
*/
183147
readonly lambdaFunctionOptions?: CustomLambdaFunctionProps;
184148
}
149+
150+
export class PgStacApiLambda extends Construct {
151+
/**
152+
* URL for the STAC API.
153+
*/
154+
readonly url: string;
155+
156+
/**
157+
* Lambda function for the STAC API.
158+
*/
159+
readonly lambdaFunction: lambda.Function;
160+
161+
/**
162+
* @deprecated - use lambdaFunction instead
163+
*/
164+
public stacApiLambdaFunction: lambda.Function;
165+
166+
constructor(scope: Construct, id: string, props: PgStacApiLambdaProps) {
167+
super(scope, id);
168+
169+
const runtime = new PgStacApiLambdaRuntime(this, "runtime", {
170+
vpc: props.vpc,
171+
subnetSelection: props.subnetSelection,
172+
db: props.db,
173+
dbSecret: props.dbSecret,
174+
enabledExtensions: props.enabledExtensions,
175+
apiEnv: props.apiEnv,
176+
lambdaFunctionOptions: props.lambdaFunctionOptions,
177+
});
178+
this.stacApiLambdaFunction = this.lambdaFunction = runtime.lambdaFunction;
179+
180+
const { api } = new LambdaApiGateway(this, "stac-api", {
181+
lambdaFunction: runtime.lambdaFunction,
182+
domainName: props.domainName ?? props.stacApiDomainName,
183+
});
184+
185+
this.url = api.url!;
186+
187+
new CfnOutput(this, "stac-api-output", {
188+
exportName: `${Stack.of(this).stackName}-url`,
189+
value: this.url,
190+
});
191+
}
192+
}
193+
194+
export interface PgStacApiLambdaProps extends PgStacApiLambdaRuntimeProps {
195+
/**
196+
* Domain Name for the STAC API. If defined, will create the domain name and integrate it with the STAC API.
197+
*
198+
* @default - undefined
199+
*/
200+
readonly domainName?: apigatewayv2.IDomainName;
201+
202+
/**
203+
* Custom Domain Name Options for STAC API.
204+
*
205+
* @deprecated Use 'domainName' instead.
206+
* @default - undefined.
207+
*/
208+
readonly stacApiDomainName?: apigatewayv2.IDomainName;
209+
}

0 commit comments

Comments
 (0)