Skip to content
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

API Gateway: AwsIntegration with Step Functions #1465

Open
rix0rrr opened this issue Jan 2, 2019 · 11 comments
Open

API Gateway: AwsIntegration with Step Functions #1465

rix0rrr opened this issue Jan 2, 2019 · 11 comments
Labels
@aws-cdk/aws-apigateway Related to Amazon API Gateway effort/medium Medium work item – several days of effort feature/service-integration Add functionality to an L2 construct to enable easier integration with another service feature-request A feature should be added or improved. p2

Comments

@rix0rrr
Copy link
Contributor

rix0rrr commented Jan 2, 2019

Came up as a question on Gitter:

Hi I am new to CDK and trying to "Create a Step Functions API Using API Gateway" using java as follows

RestApi api = new RestApi(this, "api");
        AwsIntegrationProps awsIntegrationProps = AwsIntegrationProps.builder().withService("Step Functions")
            .withAction("StartExecution").build();

    AwsIntegration awsIntegration = new AwsIntegration(awsIntegrationProps);
    Resource resource = api.getRoot().addResource("execution");
    resource.addMethod("POST", awsIntegration);

But i am getting Error "Role ARN must be specified for AWS integrations (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: fa2f7fc8-0d5c-11e9-b2bf-ab94b16eea0c)"
How do i specify Execution Role ? Ref aws doc https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-api-gateway.html

AWS integrations apparently always need a Role. The correct solution is to pass a RoleARN under the options key, but this is is validation plus a hint that we could have done locally.

Even better, we should make it as easy as on other L2 constructs to construct this required role (by doing so implicitly). We should also look into a way to set up the right permissions automatically.

@rix0rrr rix0rrr added feature-request A feature should be added or improved. @aws-cdk/aws-apigateway Related to Amazon API Gateway gap labels Jan 2, 2019
@eladb eladb self-assigned this Aug 12, 2019
@eladb eladb assigned nija-at and unassigned eladb Sep 3, 2019
@SomayaB SomayaB added language/java Related to Java bindings @aws-cdk/aws-stepfunctions Related to AWS StepFunctions labels Oct 22, 2019
@jindriago-scf
Copy link

Could we have an example of how this can be achieved?

Via the aws_apigateway.IntegrationOptions(credentials_role)?
or the root.add_method(options)?

@nija-at nija-at removed gap language/java Related to Java bindings @aws-cdk/aws-stepfunctions Related to AWS StepFunctions labels Jan 14, 2020
@nija-at nija-at changed the title API Gateway: AwsIntegration role API Gateway: AwsIntegration with Step Functions Jan 14, 2020
@nija-at nija-at added the effort/medium Medium work item – several days of effort label Feb 13, 2020
@fumiyakk
Copy link

I'm struggled with the same problem in typescript.
Could someone give me a hint to solve this?

@jindriago-scf
Copy link

jindriago-scf commented Feb 14, 2020

@fumiyakk We did it this way, its in python but I think can be translated to any language.

class AwsStateMachineIntegration(apig.AwsIntegration):
    def __init__(
            self,
            state_machine: StateMachine,
            request_templates: typing.Optional[typing.Dict[str, str]] = None,
            integration_responses: typing.Optional[typing.List[apig.IntegrationResponse]] = None,
            action_parameters: typing.Optional[typing.Mapping[str, str]] = None,
            integration_http_method: typing.Optional[str] = None,
            path: typing.Optional[str] = None,
            proxy: typing.Optional[bool] = None,
            subdomain: typing.Optional[str] = None):

        if not integration_responses:
            integration_responses = [
                apig.IntegrationResponse(
                    selection_pattern="200",
                    status_code="200",
                    response_templates={
                        "application/json": """{
                                    "executionToken": "$input.json('$.executionArn').split(':')[7].replace('"', "")"
                                }"""
                    }
                )
            ]
        
        # This is a velocity template that takes all the params in the url and inject them in the body.
        # it also takes the path and inject it in the body as an attribute path
        if not request_templates:
            request_templates = {
                "application/json": """#set($allParams = $input.params())
                        #set($pathParams = $allParams.get('path'))
                        #set($inputStr = "")
                        #set($jsonString = $input.body.substring(1))
                        #foreach($pathParamName in $pathParams.keySet())
                            #set($inputStr = $inputStr +'"'+ $pathParamName + '": "' + $util.escapeJavaScript($pathParams.get($pathParamName)) + '"')
                            #if($foreach.hasNext)  #set($inputStr = $inputStr + ',')#end
                        #end
                        #if($pathParams.size()>0) #set($inputStr = $inputStr + ",") #end
                        {"input": "{$util.escapeJavaScript($inputStr) $util.escapeJavaScript($jsonString)",
                         "stateMachineArn": \"""" + state_machine.state_machine_arn
                                    + """"
                        }"""
            }
        start_execution_role = self._get_start_execution_role(state_machine)

        super().__init__(
            service="states",
            action="StartExecution",
            action_parameters=action_parameters,
            integration_http_method=integration_http_method,
            options=IntegrationOptions(
                credentials_role=start_execution_role,
                integration_responses=integration_responses,
                request_templates=request_templates,
                passthrough_behavior=apig.PassthroughBehavior.NEVER
            ),
            path=path,
            proxy=proxy,
            subdomain=subdomain)

    @staticmethod
    def _get_start_execution_role(
            state_machine: StateMachine) -> iam.Role:
        start_execution_policy = iam.Policy(
            scope=state_machine,
            id=f"Start{state_machine.node.id}Policy",
            statements=[
                iam.PolicyStatement(
                    actions=[step_functions.Action.START_EXECUTION.value],
                    resources=[state_machine.state_machine_arn])])
        start_execution_role = iam.Role(
            scope=state_machine,
            id=f"{state_machine.node.id}ExecutionRole",
            assumed_by=iam.ServicePrincipal(
                service="apigateway.amazonaws.com"))
        start_execution_role.attach_inline_policy(
            start_execution_policy)
        return start_execution_role

I don't have too much time to explain it all at once, but hope it helps. Either way if you don't understand something let me know!

@fumiyakk
Copy link

@jindriago-scf Thank you for helping!
I could understand your code and achieved implimenting in TypeScript.

@awlsring
Copy link

awlsring commented Aug 7, 2020

@fumiyakk Any chance you could share your code? :)

@fumiyakk
Copy link

fumiyakk commented Aug 9, 2020

@awlsring
Sorry. I couldn't show the raw code because it's for work.
So, I made some abstract code. It might be broken.
I hope this could help you.

import * as cdk from '@aws-cdk/core';
import * as apigw from '@aws-cdk/aws-apigateway';
import * as iam from '@aws-cdk/aws-iam';

type Arns = { [key: string]: string }

export class SampleApiGatewayStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, Arns: Arns, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const api = new apigw.RestApi(this, 'Api', {
      restApiName: 'stateApiName',
    });

    const sampleRole = new iam.Role(this, 'StepFunctionRole',{
      assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com')
    });

    sampleRole.addToPolicy(new iam.PolicyStatement({
      resources: ['*'],
      actions: ["states:*"]
    }));

    // Get StepFunctionArn
    const str1: string = "#set($inputRoot = $input.path('$')) {"
    const str2: string = `"input": "$util.escapeJavaScript($input.json('$'))",`
    const str3: string = `"stateMachineArn":"` 
    const str4: string = `"}`
    const templateString: string = str1 + str2 + str3 + Arns["stateMachineArn"] + str4

    const requestTemplates = {
      "application/json": templateString
    }

    // Connect stateMachine with api gateway
    const stateMachineIntegration = new apigw.AwsIntegration({
      service: "states",
      action: "sampleAction",
      options: {
        credentialsRole: sampleRole,
        requestTemplates: requestTemplates, 
      }
    });

    const process1 = api.root.addResource('preprocessing')
    const process2 = process1.addResource('v1')

    process2.addMethod('POST', stateMachineIntegration, {
      methodResponses: [{
        statusCode: '200',
      }]
    });
 }
}

@nija-at nija-at added the p2 label Aug 25, 2020
@mariobittencourt
Copy link

Hi, I wonder if there is any news related to this or if anyone would have a sample code to share for the apigateway2 integration.

@zxkane
Copy link
Contributor

zxkane commented Apr 1, 2021

Hi, I wonder if there is any news related to this or if anyone would have a sample code to share for the apigateway2 integration.

I did it via L1 API.

@ericzbeard ericzbeard added the feature/service-integration Add functionality to an L2 construct to enable easier integration with another service label Apr 7, 2021
@FinHead
Copy link

FinHead commented Jul 28, 2021

Hi, I wonder if there is any news related to this or if anyone would have a sample code to share for the apigateway2 integration.

I did it via L1 API.

Huge help to me, thank you @zxkane!

@github-actions
Copy link

This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.

@github-actions github-actions bot added the closing-soon This issue will automatically close in 4 days unless further comments are made. label Jul 28, 2022
@mariobittencourt
Copy link

hi, any updates on this topic?

@github-actions github-actions bot removed the closing-soon This issue will automatically close in 4 days unless further comments are made. label Jul 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-apigateway Related to Amazon API Gateway effort/medium Medium work item – several days of effort feature/service-integration Add functionality to an L2 construct to enable easier integration with another service feature-request A feature should be added or improved. p2
Projects
None yet
Development

No branches or pull requests