forked from aws/aws-cdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
issue aws#15081: StepFunctionsRestApi implemented. Checked through ma…
…nual deployment. It is working as expected on the console.
- Loading branch information
Saqib Dhuka
committed
Sep 21, 2021
1 parent
2a629dd
commit a1af303
Showing
4 changed files
with
362 additions
and
5 deletions.
There are no files selected for viewing
153 changes: 153 additions & 0 deletions
153
packages/@aws-cdk/aws-apigateway/lib/integrations/stepFunctions.ts
This file contains 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,153 @@ | ||
import * as iam from '@aws-cdk/aws-iam'; | ||
import * as sfn from '@aws-cdk/aws-stepfunctions'; | ||
import { Token } from '@aws-cdk/core'; | ||
import { IntegrationConfig, IntegrationOptions, PassthroughBehavior } from '../integration'; | ||
import { Method } from '../method'; | ||
import { AwsIntegration } from './aws'; | ||
|
||
export interface StepFunctionsIntegrationOptions extends IntegrationOptions{ | ||
/** | ||
* Use proxy integration or normal (request/response mapping) integration. | ||
* | ||
* @default false | ||
*/ | ||
readonly proxy?: boolean; | ||
|
||
/** | ||
* Allow invoking method from AWS Console UI (for testing purposes). | ||
* | ||
* This will add another permission to the AWS Step Functions resource policy which | ||
* will allow the `test-invoke-stage` stage to invoke this handler. If this | ||
* is set to `false`, the function will only be usable from the deployment | ||
* endpoint. | ||
* | ||
* @default true | ||
*/ | ||
readonly allowTestInvoke?: boolean; | ||
|
||
/** | ||
* An IAM role that API Gateway assumes. | ||
* | ||
* @default - A role is not assumed | ||
*/ | ||
|
||
readonly credentialsRole?: iam.IRole; | ||
|
||
|
||
} | ||
/** | ||
* Integrates an AWS Step Functions to an API Gateway method. | ||
* | ||
* @example | ||
* | ||
* const handler = new sfn.StateMachine(this, 'MyStateMachine', ...); | ||
* api.addMethod('GET', new StepFunctionsIntegration(handler)); | ||
* | ||
*/ | ||
|
||
export class StepFunctionsIntegration extends AwsIntegration { | ||
private readonly handler: sfn.IStateMachine; | ||
// private readonly enableTest: boolean; | ||
|
||
constructor(handler: sfn.IStateMachine, options: StepFunctionsIntegrationOptions = { }) { | ||
//Proxy not yet available for State Machine | ||
//When it available we can set proxy to be: | ||
//proxy = options.proxy ?? true; | ||
const proxy = false; | ||
|
||
const integResponse = getIntegrationResponse(); | ||
const requestTemplates = getRequestTemplates(handler); | ||
|
||
super({ | ||
proxy: proxy, | ||
service: 'states', | ||
action: 'StartSyncExecution', | ||
options: { | ||
credentialsRole: options.credentialsRole, | ||
integrationResponses: integResponse, | ||
passthroughBehavior: PassthroughBehavior.NEVER, | ||
requestTemplates: requestTemplates, | ||
}, | ||
|
||
}); | ||
this.handler = handler; | ||
// this.enableTest = options.allowTestInvoke ?? true; | ||
} | ||
|
||
public bind(method: Method): IntegrationConfig { | ||
const bindResult = super.bind(method); | ||
const principal = new iam.ServicePrincipal('apigateway.amazonaws.com'); | ||
|
||
this.handler.grantExecution(principal, 'states:StartSyncExecution'); | ||
|
||
|
||
let stateMachineName; | ||
|
||
if (this.handler instanceof sfn.StateMachine) { | ||
//if not imported, extract the name from the CFN layer to reach the | ||
//literal value if it is given (rather than a token) | ||
stateMachineName = (this.handler.node.defaultChild as sfn.CfnStateMachine).stateMachineName; | ||
} else { | ||
throw Error('Not instance of StateMachine'); | ||
} | ||
|
||
let deploymentToken; | ||
|
||
if (!Token.isUnresolved(stateMachineName)) { | ||
deploymentToken = JSON.stringify({ stateMachineName }); | ||
} | ||
return { | ||
...bindResult, | ||
deploymentToken, | ||
}; | ||
|
||
} | ||
} | ||
|
||
function getIntegrationResponse() { | ||
const errorResponse = [ | ||
{ | ||
selectionPattern: '4\\d{2}', | ||
statusCode: '400', | ||
responseTemplates: { | ||
'application/json': `{ | ||
"error": "Bad input!" | ||
}`, | ||
}, | ||
}, | ||
{ | ||
selectionPattern: '5\\d{2}', | ||
statusCode: '500', | ||
responseTemplates: { | ||
'application/json': '"error": $input.path(\'$.error\')', | ||
}, | ||
}, | ||
]; | ||
|
||
const integResponse = [ | ||
{ | ||
statusCode: '200', | ||
responseTemplates: { | ||
'application/json': '$input.path(\'$.output\')', | ||
}, | ||
}, | ||
...errorResponse, | ||
]; | ||
|
||
return integResponse; | ||
} | ||
|
||
function getRequestTemplates(handler: sfn.IStateMachine) { | ||
const set_str: string = "#set($inputRoot = $input.path('$')) {"; | ||
const input_str: string = '"input": "$util.escapeJavaScript($input.json(\'$\'))",'; | ||
const stateMachine_str: string = '"stateMachineArn":"'; | ||
const end_str: string = '"}'; | ||
const templateString: string = set_str + input_str + stateMachine_str + String(handler.stateMachineArn) + end_str; | ||
|
||
const requestTemplates: { [contenType:string] : string } = | ||
{ | ||
'application/json': templateString, | ||
}; | ||
|
||
return requestTemplates; | ||
} |
112 changes: 112 additions & 0 deletions
112
packages/@aws-cdk/aws-apigateway/lib/stepFunctions-api.ts
This file contains 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,112 @@ | ||
import { RestApi, RestApiProps } from '@aws-cdk/aws-apigateway'; | ||
import * as iam from '@aws-cdk/aws-iam'; | ||
import * as sfn from '@aws-cdk/aws-stepfunctions'; | ||
import { Construct } from 'constructs'; | ||
import { StepFunctionsIntegration } from './integrations/stepFunctions'; | ||
import { Model } from './model'; | ||
|
||
export interface StepFunctionsRestApiProps extends RestApiProps { | ||
/** | ||
* The default State Machine that handles all requests from this API. | ||
* | ||
* This handler will be used as a the default integration for all methods in | ||
* this API, unless specified otherwise in `addMethod`. | ||
*/ | ||
readonly handler: sfn.IStateMachine; | ||
|
||
/** | ||
* If true, route all requests to the State Machine | ||
* | ||
* If set to false, you will need to explicitly define the API model using | ||
* `addResource` and `addMethod` (or `addProxy`). | ||
* | ||
* @default true | ||
*/ | ||
readonly proxy?: boolean; | ||
|
||
/** | ||
* @default - no options. | ||
*/ | ||
readonly options?: RestApiProps; | ||
} | ||
|
||
/** | ||
* Defines an API Gateway REST API with AWS Step Functions proxy integration. | ||
* | ||
* Use the `proxy` property to define a greedy proxy ("{proxy+}") and "ANY" | ||
* method from the specified path. If not defined, you will need to explicity | ||
* add resources and methods to the API. | ||
*/ | ||
|
||
export class StepFunctionsRestApi extends RestApi { | ||
constructor(scope: Construct, id: string, props: StepFunctionsRestApiProps) { | ||
if ((props.options && props.options.defaultIntegration) || props.defaultIntegration) { | ||
throw new Error('Cannot specify "defaultIntegration" since Step Functions integration is automatically defined'); | ||
} | ||
|
||
const apiRole = getRole(scope, props); | ||
const methodResp = getMethodResponse(); | ||
|
||
super(scope, id, { | ||
defaultIntegration: new StepFunctionsIntegration(props.handler, { | ||
credentialsRole: apiRole, | ||
}), | ||
...props.options, | ||
...props, | ||
}); | ||
|
||
this.root.addMethod('ANY', new StepFunctionsIntegration(props.handler, { | ||
credentialsRole: apiRole, | ||
}), { | ||
methodResponses: [ | ||
...methodResp, | ||
], | ||
}); | ||
} | ||
} | ||
|
||
function getRole(scope: Construct, props: StepFunctionsRestApiProps): iam.Role { | ||
const apiName: string = props.handler + '-apiRole'; | ||
const apiRole = new iam.Role(scope, apiName, { | ||
assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), | ||
}); | ||
|
||
apiRole.attachInlinePolicy( | ||
new iam.Policy(scope, 'getPolicy', { | ||
statements: [ | ||
new iam.PolicyStatement({ | ||
actions: ['states:StartSyncExecution'], | ||
effect: iam.Effect.ALLOW, | ||
resources: ['*'], | ||
}), | ||
], | ||
}), | ||
); | ||
|
||
return apiRole; | ||
} | ||
|
||
function getMethodResponse() { | ||
const methodResp = [ | ||
{ | ||
statusCode: '200', | ||
responseModels: { | ||
'application/json': Model.EMPTY_MODEL, | ||
}, | ||
}, | ||
{ | ||
statusCode: '400', | ||
responseModels: { | ||
'application/json': Model.ERROR_MODEL, | ||
}, | ||
}, | ||
{ | ||
statusCode: '500', | ||
responseModels: { | ||
'application/json': Model.ERROR_MODEL, | ||
}, | ||
}, | ||
]; | ||
|
||
return methodResp; | ||
} |
This file contains 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
Oops, something went wrong.