Skip to content

Commit

Permalink
feat: support api gateway and path based CORS (#305)
Browse files Browse the repository at this point in the history
  • Loading branch information
thantos authored Mar 1, 2023
1 parent 9b9e570 commit 399f173
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 9 deletions.
65 changes: 57 additions & 8 deletions packages/@eventual/aws-cdk/src/command-service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import {
HttpApi,
HttpRouteProps,
HttpMethod,
HttpRouteProps
CorsHttpMethod,
} from "@aws-cdk/aws-apigatewayv2-alpha";
import { HttpIamAuthorizer } from "@aws-cdk/aws-apigatewayv2-authorizers-alpha";
import { HttpLambdaIntegration } from "@aws-cdk/aws-apigatewayv2-integrations-alpha";
import { ENV_NAMES, sanitizeFunctionName } from "@eventual/aws-runtime";
import {
commandRpcPath,
isDefaultNamespaceCommand
} from "@eventual/core";
import { Arn, aws_iam, Lazy, Stack } from "aws-cdk-lib";
import { commandRpcPath, isDefaultNamespaceCommand } from "@eventual/core";
import { Arn, aws_iam, Duration, Lazy, Stack } from "aws-cdk-lib";
import { Effect, IGrantable, PolicyStatement } from "aws-cdk-lib/aws-iam";
import type { Function, FunctionProps } from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";
Expand All @@ -20,7 +18,7 @@ import type {
CommandFunction,
InternalCommandFunction,
InternalCommandName,
InternalCommands
InternalCommands,
} from "./build-manifest";
import type { EventService } from "./event-service";
import { grant } from "./grant";
Expand All @@ -37,11 +35,47 @@ export type CommandProps<Service> = {
default?: CommandHandlerProps;
} & Partial<ServiceEntityProps<Service, "Command", CommandHandlerProps>>;

export interface CorsOptions {
/**
* Specifies whether credentials are included in the CORS request.
* @default false
*/
readonly allowCredentials?: boolean;
/**
* Represents a collection of allowed headers.
* @default - No Headers are allowed.
*/
readonly allowHeaders?: string[];
/**
* Represents a collection of allowed HTTP methods.
* OPTIONS will be added automatically.
*
* @default - OPTIONS
*/
readonly allowMethods?: CorsHttpMethod[];
/**
* Represents a collection of allowed origins.
* @default - No Origins are allowed.
*/
readonly allowOrigins?: string[];
/**
* Represents a collection of exposed headers.
* @default - No Expose Headers are allowed.
*/
readonly exposeHeaders?: string[];
/**
* The duration that the browser should cache preflight request results.
* @default Duration.seconds(0)
*/
readonly maxAge?: Duration;
}

export interface CommandsProps<Service = any> extends ServiceConstructProps {
activityService: ActivityService<Service>;
overrides?: CommandProps<Service>;
eventService: EventService;
workflowService: WorkflowService;
cors?: CorsOptions;
}

/**
Expand Down Expand Up @@ -168,6 +202,17 @@ export class CommandService<Service = any> {
"default",
this.serviceCommands.default
),
corsPreflight: props.cors
? {
...props.cors,
allowMethods: Array.from(
new Set([
...(props.cors.allowMethods ?? []),
CorsHttpMethod.OPTIONS,
])
),
}
: undefined,
});

this.finalize();
Expand Down Expand Up @@ -240,7 +285,11 @@ export class CommandService<Service = any> {
}
if (command.path) {
self.gateway.addRoutes({
path: command.path,
// itty router supports paths in the form /*, but api gateway expects them in the form /{proxy+}
path:
command.path === "*"
? "/{proxy+}"
: (command.path as string).replace(/\*/g, "{proxy+}"),
methods: [
(command.method as HttpMethod | undefined) ?? HttpMethod.GET,
],
Expand Down
1 change: 0 additions & 1 deletion packages/@eventual/aws-cdk/src/deep-composite-principal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ export class DeepCompositePrincipal extends CompositePrincipal {
override addToPrincipalPolicy(
statement: PolicyStatement
): AddToPrincipalPolicyResult {
console.log(statement);
const res = this._principals.map((p) => p.addToPrincipalPolicy(statement));
const added = res.every((s) => s.statementAdded);
if (added) {
Expand Down
3 changes: 3 additions & 0 deletions packages/@eventual/aws-cdk/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
CommandService,
Commands,
SystemCommands,
CorsOptions,
} from "./command-service";
import { DeepCompositePrincipal } from "./deep-composite-principal.js";
import { EventService } from "./event-service";
Expand Down Expand Up @@ -94,6 +95,7 @@ export interface ServiceProps<Service = any> {
* Override properties of Subscription Functions within the Service.
*/
subscriptions?: SubscriptionOverrides<Service>;
cors?: CorsOptions;
system?: {
/**
* Configuration properties for the workflow orchestrator
Expand Down Expand Up @@ -239,6 +241,7 @@ export class Service<S = any> extends Construct {
overrides: props.commands,
eventService: this.eventService,
workflowService: workflowService,
cors: props.cors,
...serviceConstructProps,
});
proxyCommandService._bind(this.commandService);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ export function createCommandWorker({
try {
const response = await router.handle(request);
if (response === undefined) {
if (request.method === "OPTIONS") {
return new HttpResponse(undefined, {
// CORS expects a 204 or 200, using 204 to match API Gateway
// and accurately reflect NO CONTENT
status: 204,
});
}
return new HttpResponse(
`Not Found: ${request.method} ${request.url}`,
{
Expand Down

0 comments on commit 399f173

Please sign in to comment.