-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support api gateway and path based CORS #305
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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"; | ||
|
@@ -20,7 +18,7 @@ import type { | |
CommandFunction, | ||
InternalCommandFunction, | ||
InternalCommandName, | ||
InternalCommands | ||
InternalCommands, | ||
} from "./build-manifest"; | ||
import type { EventService } from "./event-service"; | ||
import { grant } from "./grant"; | ||
|
@@ -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; | ||
} | ||
|
||
/** | ||
|
@@ -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(); | ||
|
@@ -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 === "*" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this fragile? What about /abc/* There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thats fine, would become |
||
? "/{proxy+}" | ||
: (command.path as string).replace(/\*/g, "{proxy+}"), | ||
methods: [ | ||
(command.method as HttpMethod | undefined) ?? HttpMethod.GET, | ||
], | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,11 @@ export function createCommandWorker({ | |
try { | ||
const response = await router.handle(request); | ||
if (response === undefined) { | ||
if (request.method === "OPTIONS") { | ||
return new HttpResponse(undefined, { | ||
status: 204, | ||
}); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why 204? A comment would help There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added // CORS expects a 204 or 200, using 204 to match API Gateway
// and accurately reflect NO CONTENT |
||
return new HttpResponse( | ||
`Not Found: ${request.method} ${request.url}`, | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we allow this to be configured per command also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe later, but API Gateway http doesn't support that. The "custom" approach which doesn't use the infra config would support per operation.