-
Notifications
You must be signed in to change notification settings - Fork 1
New: [AEA-6256] - StateMachine construct #604
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
Merged
Merged
Changes from all commits
Commits
Show all changes
47 commits
Select commit
Hold shift + click to select a range
02b0af2
refactor: api gateway from cpt for reuse
tstephen-nhs 455b657
Merge branch 'main' into aea-6254-cdk-api-gateway
tstephen-nhs d3594ca
Merge branch 'main' into aea-6254-cdk-api-gateway
tstephen-nhs bb83c29
fix: enforce expected role
tstephen-nhs 74d0de2
fix: make LogGroup child of API gateway
tstephen-nhs c7d714d
chore: add sonarqube plugin for 'clean as you code'
tstephen-nhs f2e9325
fix: protect against enabling csoc with no destination
tstephen-nhs 0ac46b1
chore: clean imports
tstephen-nhs b500519
chore: ignore SQ rather than add extra var declaration
tstephen-nhs 4faca4a
feat: add state machine construct inc. api gateway endpoint
tstephen-nhs f701083
chore: fix 'any' use
tstephen-nhs 27484f9
docs: JS doc
tstephen-nhs 1346790
docs: jsdoc, plus String.raw for regex
tstephen-nhs ccb5129
docs: example usage of StateMachine
tstephen-nhs f4d4506
docs: example of ApiGateway use
tstephen-nhs e35ce32
refactor: centralise constants
tstephen-nhs c734151
refactor: centralise constants
tstephen-nhs d464766
Upgrade: [dependabot] - bump NHSDigital/eps-common-workflows/.github/…
dependabot[bot] 831746b
Upgrade: [dependabot] - bump NHSDigital/eps-common-workflows/.github/…
dependabot[bot] 90c37b7
Upgrade: [dependabot] - bump NHSDigital/eps-common-workflows/.github/…
dependabot[bot] 4f7415c
Upgrade: [dependabot] - bump NHSDigital/eps-common-workflows/.github/…
dependabot[bot] 9048e4f
Upgrade: [dependabot] - bump NHSDigital/eps-common-workflows/.github/…
dependabot[bot] cd35a79
Upgrade: [dependabot] - bump constructs from 10.5.1 to 10.6.0 (#626)
dependabot[bot] 76a062b
Upgrade: [dependabot] - bump @vitest/coverage-v8 from 4.1.0 to 4.1.2 …
dependabot[bot] f231ac7
Upgrade: [dependabot] - bump eslint from 10.0.3 to 10.1.0 (#632)
dependabot[bot] 0874ea7
Upgrade: [dependabot] - bump @aws-sdk/client-s3 from 3.1013.0 to 3.10…
dependabot[bot] 8fe08e2
Upgrade: [dependabot] - bump picomatch from 2.3.1 to 2.3.2 (#638)
dependabot[bot] fa0ae51
Upgrade: [dependabot] - bump aws-cdk from 2.1112.0 to 2.1114.1 (#636)
dependabot[bot] 37bdda4
Upgrade: [dependabot] - bump @aws-sdk/client-lambda from 3.1013.0 to …
dependabot[bot] 6085fe1
Upgrade: [dependabot] - bump @typescript-eslint/eslint-plugin from 8.…
dependabot[bot] 72bb3f9
Upgrade: [dependabot] - bump @aws-sdk/client-cloudformation from 3.10…
dependabot[bot] 5080ce5
Upgrade: [dependabot] - bump @aws-sdk/client-route-53 from 3.1013.0 t…
dependabot[bot] 602b2f0
Upgrade: [dependabot] - bump handlebars from 4.7.8 to 4.7.9 (#639)
dependabot[bot] dc74bf6
revert git secrets install
tstephen-nhs 4ccfaf1
fix: use postCreate to avoid git-secrets failing on second and subseq…
tstephen-nhs c5d9ba9
docs: add copilot instructions and teach it to write JSDoc
tstephen-nhs af7a124
docs: rereview jsdoc in light of new copilot instructions
tstephen-nhs 6107867
Merge branch 'main' into aea-6256-cdk-statemachine
tstephen-nhs 23f64d3
chore: placate SQ
tstephen-nhs 525fdcc
Merge branch 'main' into aea-6256-cdk-statemachine
tstephen-nhs 8956b70
chore: npm audit fix
tstephen-nhs 8ca91e6
fix: typo on cache strategy
tstephen-nhs fb774c5
fix: typo in const name
tstephen-nhs 9fd0795
fix: diagnostics in error response
tstephen-nhs 9d2e21f
fix: copy paste naming error
tstephen-nhs 0a2a573
fix: typo on log stream resource
tstephen-nhs 464dc01
fix: enumerate potential status codes
tstephen-nhs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
74 changes: 74 additions & 0 deletions
74
packages/cdkConstructs/src/constructs/RestApiGateway/StateMachineEndpoint.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| import {IResource, PassthroughBehavior, StepFunctionsIntegration} from "aws-cdk-lib/aws-apigateway" | ||
| import {IRole} from "aws-cdk-lib/aws-iam" | ||
| import {HttpMethod} from "aws-cdk-lib/aws-lambda" | ||
| import {Construct} from "constructs" | ||
| import {stateMachineRequestTemplate} from "./templates/stateMachineRequest.js" | ||
| import {stateMachine200ResponseTemplate, stateMachineErrorResponseTemplate} from "./templates/stateMachineResponses.js" | ||
| import {ExpressStateMachine} from "../StateMachine.js" | ||
|
|
||
| /** Parameters used to create an API endpoint backed by a Step Functions Express workflow. */ | ||
| export interface StateMachineEndpointProps { | ||
| /** Parent API resource under which the state machine endpoint is added. */ | ||
| parentResource: IResource | ||
| /** Path segment used to create the child API resource. */ | ||
| readonly resourceName: string | ||
| /** HTTP verb bound to the Step Functions integration. */ | ||
| readonly method: HttpMethod | ||
| /** Invocation role used by API Gateway when starting workflow executions. */ | ||
| restApiGatewayRole: IRole | ||
| /** State machine wrapper construct providing the target workflow ARN and integration target. */ | ||
| stateMachine: ExpressStateMachine | ||
| } | ||
|
|
||
| /** Adds an API Gateway resource/method that starts an Express Step Functions execution. */ | ||
| export class StateMachineEndpoint extends Construct { | ||
| /** API resource created by this construct. */ | ||
| resource: IResource | ||
|
|
||
| /** Wires request and response mapping templates for JSON and FHIR payload flows. */ | ||
| public constructor(scope: Construct, id: string, props: StateMachineEndpointProps) { | ||
| super(scope, id) | ||
|
|
||
| const requestTemplate = stateMachineRequestTemplate(props.stateMachine.stateMachine.stateMachineArn) | ||
|
|
||
| const resource = props.parentResource.addResource(props.resourceName) | ||
| resource.addMethod(props.method, StepFunctionsIntegration.startExecution(props.stateMachine.stateMachine, { | ||
| credentialsRole: props.restApiGatewayRole, | ||
| passthroughBehavior: PassthroughBehavior.WHEN_NO_MATCH, | ||
| requestTemplates: { | ||
| "application/json": requestTemplate, | ||
| "application/fhir+json": requestTemplate | ||
| }, | ||
| integrationResponses: [ | ||
| { | ||
| statusCode: "200", | ||
| responseTemplates: { | ||
| "application/json": stateMachine200ResponseTemplate | ||
| } | ||
| }, | ||
| { | ||
| statusCode: "400", | ||
| selectionPattern: String.raw`^4\d{2}.*`, | ||
| responseTemplates: { | ||
| "application/json": stateMachineErrorResponseTemplate("400") | ||
| } | ||
| }, | ||
| { | ||
| statusCode: "500", | ||
| selectionPattern: String.raw`^5\d{2}.*`, | ||
| responseTemplates: { | ||
| "application/json": stateMachineErrorResponseTemplate("500") | ||
| } | ||
| } | ||
| ] | ||
| }), { | ||
| methodResponses: [ | ||
| { statusCode: "200" }, | ||
| { statusCode: "400" }, | ||
| { statusCode: "500" } | ||
| ] | ||
| }) | ||
|
|
||
| this.resource = resource | ||
| } | ||
| } |
60 changes: 60 additions & 0 deletions
60
packages/cdkConstructs/src/constructs/RestApiGateway/templates/stateMachineRequest.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* eslint-disable max-len */ | ||
| /** | ||
| * @returns API Gateway request mapping template for StartExecution payloads. | ||
| */ | ||
| export const stateMachineRequestTemplate = (stateMachineArn: string) => { | ||
| return `## Velocity Template used for API Gateway request mapping template | ||
| ## "@@" is used here as a placeholder for '"' to avoid using escape characters. | ||
|
|
||
| #set($includeHeaders = true) | ||
| #set($includeQueryString = true) | ||
| #set($includePath = true) | ||
| #set($requestContext = '') | ||
|
|
||
| #set($inputString = '') | ||
| #set($allParams = $input.params()) | ||
| #set($allParams.header.apigw-request-id = $context.requestId) | ||
| { | ||
| "stateMachineArn": "${stateMachineArn}", | ||
| #set($inputString = "$inputString,@@body@@: $input.body") | ||
| #if ($includeHeaders) | ||
| #set($inputString = "$inputString, @@headers@@:{") | ||
| #foreach($paramName in $allParams.header.keySet()) | ||
| #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.header.get($paramName))@@") | ||
| #if($foreach.hasNext) | ||
| #set($inputString = "$inputString,") | ||
| #end | ||
| #end | ||
| #set($inputString = "$inputString }") | ||
| #end | ||
| #if ($includeQueryString) | ||
| #set($inputString = "$inputString, @@queryStringParameters@@:{") | ||
| #foreach($paramName in $allParams.querystring.keySet()) | ||
| #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.querystring.get($paramName))@@") | ||
| #if($foreach.hasNext) | ||
| #set($inputString = "$inputString,") | ||
| #end | ||
| #end | ||
| #set($inputString = "$inputString }") | ||
| #end | ||
| #if ($includePath) | ||
| #set($inputString = "$inputString, @@pathParameters@@:{") | ||
| #foreach($paramName in $allParams.path.keySet()) | ||
| #set($inputString = "$inputString @@$paramName@@: @@$util.escapeJavaScript($allParams.path.get($paramName))@@") | ||
| #if($foreach.hasNext) | ||
| #set($inputString = "$inputString,") | ||
| #end | ||
| #end | ||
| #set($inputString = "$inputString }") | ||
| #end | ||
| ## Check if the request context should be included as part of the execution input | ||
| #if($requestContext && !$requestContext.empty) | ||
| #set($inputString = "$inputString,") | ||
| #set($inputString = "$inputString @@requestContext@@: $requestContext") | ||
| #end | ||
| #set($inputString = "$inputString}") | ||
| #set($inputString = $inputString.replaceAll("@@",'"')) | ||
| #set($len = $inputString.length() - 1) | ||
| "input": "{$util.escapeJavaScript($inputString.substring(1,$len))}" | ||
| }` | ||
| } |
64 changes: 64 additions & 0 deletions
64
packages/cdkConstructs/src/constructs/RestApiGateway/templates/stateMachineResponses.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /* eslint-disable max-len */ | ||
| /** VTL response template that unwraps successful workflow output and forwards status and headers. */ | ||
| export const stateMachine200ResponseTemplate = `#set($payload = $util.parseJson($input.path('$.output'))) | ||
| #set($context.responseOverride.status = $payload.Payload.statusCode) | ||
| #set($allHeaders = $payload.Payload.headers) | ||
| #foreach($headerName in $allHeaders.keySet()) | ||
| #set($context.responseOverride.header[$headerName] = $allHeaders.get($headerName)) | ||
| #end | ||
| $payload.Payload.body` | ||
|
|
||
| interface ErrorMap { | ||
| [key: string]: { | ||
| code: string | ||
| severity: string | ||
| diagnostics: string | ||
| codingCode: string | ||
| codingDisplay: string | ||
| } | ||
| } | ||
|
|
||
| const getOperationOutcome = (status: string) => { | ||
| const errorMap: ErrorMap = { | ||
| 400: { | ||
| code: "value", | ||
| severity: "error", | ||
| diagnostics: "Invalid request.", | ||
| codingCode: "BAD_REQUEST", | ||
| codingDisplay: "400: The Server was unable to process the request" | ||
| }, | ||
| 500: { | ||
| code: "exception", | ||
| severity: "fatal", | ||
| diagnostics: "Unknown Error.", | ||
| codingCode: "SERVER_ERROR", | ||
| codingDisplay: "500: The Server has encountered an error processing the request." | ||
| } | ||
| } | ||
|
|
||
| return JSON.stringify({ | ||
| ResourceType: "OperationOutcome", | ||
| issue: [ | ||
| { | ||
| code: errorMap[status].code, | ||
| severity: errorMap[status].severity, | ||
| diagnostics: errorMap[status].diagnostics, | ||
| details: { | ||
| coding: [ | ||
| { | ||
| system: "https://fhir.nhs.uk/CodeSystem/http-error-codes", | ||
| code: errorMap[status].codingCode, | ||
| display: errorMap[status].codingDisplay | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| ] | ||
| }) | ||
| } | ||
|
|
||
| /** | ||
| * @returns VTL response template that maps workflow failures to FHIR OperationOutcome payloads. | ||
| */ | ||
| export const stateMachineErrorResponseTemplate = (status: string) => `#set($context.responseOverride.header["Content-Type"] ="application/fhir+json") | ||
| ${getOperationOutcome(status)}` | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.