Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating aws lambda integrated api gateway resource with boto3

Im trying to, as the title dictates, create a resource with a method that triggers a lambda function with boto3 python library.

Im doing the following.

First, I create the resource

new_endpoint_response = aws_apigateway.create_resource(
        restApiId = 'xxxxxxxx',
        parentId = 'xxxxxxxx',
        pathPart = event['Configure']
    )

Then, the post method

put_method_response = aws_apigateway.put_method(
        restApiId = 'xxxxxxxxxxx',
        resourceId = new_endpoint_response['id'],
        httpMethod = 'POST',
        authorizationType = 'NONE'
    )

And finally, assingn a lambda function to that method with

aws_apigateway.put_integration(
        restApiId = 'xxxxxxxxxx',
        resourceId = new_endpoint_response['id'],
        httpMethod = 'POST', 
        integrationHttpMethod = 'POST',
        type = 'AWS',
        uri = 'LAMBDA ARN'
    )

Here is where I'm having some issues. When I try to do the last step, I always get

An error occurred (BadRequestException) when calling the PutIntegration operation: AWS ARN for integration must contain path or action

And I have no idea why that is. From what I have searched, the uri required is in fact the api invocation url, problem is I have no idea what that means or how to obtain it. The example shown is the following.

arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunctionAPI.Arn}/invocations

How can I make it so that invocation URL invokes the lambda function I want and how do I even get that invocation url?

like image 503
Manuel Avatar asked Jan 26 '23 14:01

Manuel


1 Answers

Woohoo. This is a year old so you probably found another way. But I'm going to put this in here for the next person that comes along. AWS is not my favorite at the moment r/unpopularopinion

First off, figured it out by using a combination of these three:

  • Boto3 docs
  • Lambda Configurations
  • This SO post
  1. A lambda function has to exist first, you can do this by creating one through the aws CLI, the GUI or by using a boto3 function which is what got me to step two:
 lambda_client = boto3.client('lambda')
 new_lambda = lambda_client.create_function(
    FunctionName='HelloWorld',
    Runtime='nodejs12.x',
    Role='arn:aws:iam::<user_id>:role/HelloWorld',
    Handler='handler.handler',
    Code={ 'ZipFile': <zip_file_object_from_s3> },
    Description='Hello World Function',
    Publish=True,
 )

 # You can then get at least part of the invocation uri here:
 print(new_lambda['FunctionArn'])
  1. Create a Rest Api with the boto3
  # Create rest api
  rest_api = api_client.create_rest_api(
    name='GreatApi'
  )

  print(rest_api)

  rest_api_id = rest_api["id"]

  # Get the rest api's root id
  root_resource_id = api_client.get_resources(
    restApiId=rest_api_id
  )['items'][0]['id']
    
  # Create an api resource
  api_resource = api_client.create_resource(
    restApiId=rest_api_id,
    parentId=root_resource_id,
    pathPart='greeting'
  )

  api_resource_id = api_resource['id']

  # Add a post method to the rest api resource
  api_method = api_client.put_method(
    restApiId=rest_api_id,
    resourceId=api_resource_id,
    httpMethod='GET',
    authorizationType='NONE',
    requestParameters={
      'method.request.querystring.greeter': False
    }
  )

  print(api_method)

  put_method_res = api_client.put_method_response(
    restApiId=rest_api_id,
    resourceId=api_resource_id,
    httpMethod='GET',
    statusCode='200'
  )

  print(put_method_res)

  # The uri comes from a base lambda string with the function ARN attached to it
  arn_uri="arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:<user_id>:function:HelloWorld/invocations"
 
  put_integration = api_client.put_integration(
    restApiId=rest_api_id,
    resourceId=api_resource_id,
    httpMethod='GET',
    type='AWS',
    integrationHttpMethod='POST',
    uri=arn_uri
    credentials='arn:aws:iam::<user_id>:role/HelloWorldRole',
    requestTemplates={
      "application/json":"{\"greeter\":\"$input.params('greeter')\"}"
    },
  )

  print(put_integration)

  put_integration_response = api_client.put_integration_response(
    restApiId=rest_api_id,
    resourceId=api_resource_id,
    httpMethod='GET',
    statusCode='200',
    selectionPattern=''
  )

  print(put_integration_response)

  # this bit sets a stage 'dev' that is built off the created apigateway
  # it will look something like this:
  # https://<generated_api_id>.execute-api.<region>.amazonaws.com/dev
  deployment = api_client.create_deployment(
    restApiId=rest_api_id,
    stageName='dev',
  )

  # all that done we can then send a request to invoke our lambda function
  # https://123456.execute-api.us-east-1.amazonaws.com/dev?greeter=John
  print(deployment)

Bit more involved but I think that without the apiGateway you can't actually make a resource. Once I get a minute I'll build out an example serverless repo.

like image 157
ContextCue Avatar answered Jan 31 '23 08:01

ContextCue