AWS endpoint not being deployed to stages when using Serverless - amazon-web-services

I'm trying to add a new endpoint to an existing service, and while it shows on the API Gateway Resources page, it's not showing on the Stages page. Hitting the endpoint returns the header x-amzn-ErrorType as IncompleteSignatureException and an error that includes the JWT token and not a valid key=value pair (missing equal-sign) in Authorization header.
Our setup uses a swagger file to define the endpoints, and uses x-amazon-apigateway-integration to link the endpoint to the lambda function. On first deployment of the new endpoint, we had some problems as this integration was setup wrong, but has since been corrected to match the others (suspect this is where the problem lies).
I've tried making sure that the new endpoint config matches that of other working endpoints; I've removed the endpoint, redeployed, added it back and redeployed; I've renamed the lambda. None of these have worked.
The swagger file looks like:
/companies/{id}/info:
get:
consumes:
- application/json
produces:
- application/json
responses:
"200":
description: successful operation
headers:
Access-Control-Allow-Origin:
type: string
x-amazon-apigateway-integration:
uri:
Fn::Join:
- ""
- - Fn::Join:
- ""
- - "arn:aws:apigateway:"
- Ref: AWS::Region
- ":lambda:path/2015-03-31/functions/"
- Fn::GetAtt:
- GetCompanyInfoLambdaFunction
- Arn
- "/invocations"
httpMethod: POST
type: aws_proxy
post:
#... this method works fine with same config but different lambda
Any ideas as to how to fix this? Thanks

Related

How to enable cache in AWS APIGateway using OpenApi yaml?

I have a yaml file for the API Gateway integration like this:
/users/{userId}:
get:
description: Get user details
parameters:
- description: Valid user id
in: path
name: userId
required: true
schema:
type: string
responses:
'200':
content: {}
description: Success
headers:
Access-Control-Allow-Origin:
schema:
type: string
'400':
content: {}
description: Invalid user id
security:
- NodeJsAuth: []
summary: Get User Id Details
tags:
- User
x-amazon-apigateway-integration:
connectionId: ${stageVariables.vpcLinkId}
connectionType: VPC_LINK
httpMethod: GET
passthroughBehavior: when_no_match
requestParameters:
integration.request.path.userId: method.request.path.userId
responses:
default:
responseParameters:
method.response.header.Access-Control-Allow-Origin: '''*'''
statusCode: '200'
type: http_proxy
uri: '#{EksElbUri}#/user/{userId}'
I want to enable cache for this method. I know I can enable it manually but I want to do it in YAML file so it could be easier to execute.
I have my stage enabled the cache already (via AWS Console UI). However I could not find anywhere that is mentioning how to enable cache for this method ONLY.
I am aware that once enabled the cache in stage, it will enabled for all GET endpoints and I have many GET endpoints but I only want this one to be cached.
Is there a way that I can specify the cache in OPEN-API so I no need to disable all the other GET endpoint one by one manually?
Thank you.
What will you'll find easier is edit the API in the API GW Console, enabling cache. Deploy the API to your stage. Then go to Stages -> your stage, and export the API in whatever format you are currently editing in. This is what I do saves you having indentation problems, and wasting time trying to find the exact equivalent syntax.
Once you have done that once your file is easier to edit and you can typically figure out the edits you want to make.

AWS API Gateway and Lambda integration with resources on different Cloudformation stacks

I want to integrate a lambda function to an API gateway so that when I do a POST to the path defined on the API gateway the Lambda gets executed and returns a value.
Now, in my current project we currently have 2 Cloudformation templates:
- One that is generic and contains the definition of recourses common to all development environments
- And another non-generic one that deploys different resources depending on the environment passed as a paramater (dev, prod, etc).
In the non generic I have defined the lambda function, as well as the Deployment and Stage.
In the generic CF template I have defined the APIGateway as this:
Resources:
RecargakiApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Body:
swagger: "2.0"
info:
version: "VersionTimestamp"
title: "Some API"
host: "some.host"
schemes:
- "https"
paths:
/payment:
post:
produces:
- "application/json"
responses:
"200":
description: "200 response"
schema:
$ref: "#/definitions/Empty"
x-amazon-apigateway-integration:
credentials:
Fn::ImportValue:
"lambda-credentials-outputvalue-in-another-generic-stack"
uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda::${AWS::Region}:${AWS::AccountId}:function:${lambdaName}/invocations"
- lambdaName: "${stageVariables.lambda_name}"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
timeoutInMillis: 5000
httpMethod: "POST"
contentHandling: "CONVERT_TO_TEXT"
type: "aws_proxy"
definitions:
Empty:
type: "object"
title: "Empty Schema"
Description: "Desc"
Name: "Name"
EndpointConfiguration:
Types:
- REGIONAL
Now according to the docs on AWS proxy integration it is possible to construct the lambda uri like this:
arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/arn:aws:lambda::<account_id>:function:${stageVariables.<function_variable_name>}/invocations
I tried to construct the uri according to that format but I get this error:
Unable to put integration on 'POST' for resource at path '/payment': Invalid function ARN or invalid uri (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException
In all the examples I've seen, people assume the Lambda function to be integrated is located in the same CF template/stack as the API Gateway resource, but I have no idea how to reference the function's ARN and/or name in the Swagger definition of the API Gateway when the function is actually located in a different CF stack.
I've also tried referencing a stage variable that would contain the full URI like:
uri: "${stageVariables.functionURI}" # the URI would be constructed in the non generic stack in the format stated by the docs
But it fails with:
Unable to put integration on 'POST' for resource at path '/payment': Invalid ARN specified in the request (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException
Any help is greatly appreciated.

How to re-use my x-amazon-apigateway-integration definition throughout Swagger YAML document?

I am currently using Swagger to define an API with many end-points, and each one of those end-points all have the same definition for the 'x-amazon-apigateway-integration' key. I would like to define this somewhere in the document, and re-use that definition through-out.
Either I am not understanding how the definition should be defined, I am not placing it in the correct location or a mix of the two. I have tried defining this definition within 'definitions', and as some alias under it's own key. The definition (with key information removed) is:
x-amazon-apigateway-integration:
responses:
default:
statusCode: '200'
passthroughBehavior: when_no_match
httpMethod: POST
uri: >-
arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/<lambda arn>/invocations
credentials: '<role arn>'
type: aws
requestTemplates: "application/json": "<object definition>"
I have tried defining this as an alias under it's own key (not definitions, but the same base scope):
amazon:
Amazon: &Amazon
- responses:
default:
statusCode: '200'
- passthroughBehavior: when_no_match
- httpMethod: POST
- uri: >-
arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/<lambda arn>/invocations
- credentials: '<role arn>'
- type: aws
- requestTemplates:
"application/json": "<object definition>"
To use, I have the following:
x-amazon-apigateway-integration:
*Amazon
The error received on API Gateway import is 'Unable to parse API definition because of a malformed integration at path /'
I have also tried defining this under 'definitions', and using 'ref' to access it:
definitions:
Amazon:
type: object
x-amazon-apigateway-integration:
responses:
default:
statusCode: '200'
passthroughBehavior: when_no_match
httpMethod: POST
uri: >-
arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/<lambda arn>/invocations
credentials: '<role arn>'
type: aws
requestTemplates:
"application/json": "<object definition>"
To use, I have the following:
x-amazon-apigateway-integration:
$ref: '#/definitions/Amazon'
On import to API Gateway I receive the following error(s):
Your API was not imported due to errors in the Swagger file.
Unable to create model for 'Amazon': Invalid model specified: Validation Result: warnings : [], errors : [Invalid model schema specified. Unsupported keyword(s): ["x-amazon-apigateway-integration"]]
Additionally, these warnings were found:
Unknown integration type 'null' for 'POST /'. Ignoring.
Thank you in advance for your help.
Using YAML anchors seems like a good idea. The correct syntax is as follows.
Add the following on the root level of your OpenAPI file:
x-definitions: # <--- "x-" before "definitions" prevents it from being
# attempted to be parsed as an OpenAPI Schema object.
Amazon:
type: object
x-amazon-apigateway-integration: &Amazon # <--- "&Amazon" is the anchor
responses:
default:
statusCode: '200'
passthroughBehavior: when_no_match
httpMethod: POST
uri: >-
arn:aws:apigateway:<region>:lambda:path/2015-03-31/functions/<lambda arn>/invocations
credentials: '<role arn>'
type: aws
requestTemplates:
"application/json": "<object definition>"
Then you can refer to the anchor like this:
x-amazon-apigateway-integration: *Amazon
However, it might be that AWS parser does not support YAML anchors (&..., *...). In that case you can try pre-processing your definition using a parser that can resolve YAML anchors and then feed the resolved file to AWS.
As of 24th April 2020, it appears as though AWS API Gateway does not support referencing x-amazon-apigateway-integration components in OpenAPI v3 files, as trying to import the example from https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-extensions-integrations.html fails with
Your API was not imported due to errors in the Swagger file.
Unknown integration type 'null' for 'GET /'. Ignoring.
Unknown integration type 'null' for 'GET /pets'. Ignoring.
Unknown integration type 'null' for 'GET /checkout'. Ignoring.
It looks as though pre-processing the file is currently the only option to avoid repeated integration definitions

Swagger definition for an AWS Api-Gateway Lambda Proxy endpoint

FYI - I've checked similar issues related to this, but none solves my problem.
I'm trying to create the Swagger definition for a number of APIs under AWS Api-Gateway. I'm able to successfully do this for other(POST, GET) endpoints from an auto-generated YAML configuration I downloaded from the API Stage.
But I encountered issues when I tried to do same for an Api-Gateway endpoint with Lambda Proxy Integration: Error from Swagger editor.swagger.io
Below is my YAML definition for the failing endpoint:
swagger: "2.0"
info:
version: "2018-04-18T17-09-07Z"
title: "XXX API"
host: "api.xxx.io"
schemes:
- "https"
parameters:
stage:
name: stage
in: path
type: string
enum: [ staging, production]
required: true
paths:
/env/{stage}/{proxy+}:
x-amazon-apigateway-any-method:
produces:
- "application/json"
parameters:
- $ref: '#/parameters/stage'
- name: "proxy"
in: "path"
required: true
type: "string"
responses: {}
x-amazon-apigateway-integration:
uri: "arn:aws:apigateway:eu-central-1:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-central-1:xxxxxxxxx:function:environment/invocations"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
httpMethod: "POST"
cacheNamespace: "4vbcjm"
cacheKeyParameters:
- "method.request.path.proxy"
contentHandling: "CONVERT_TO_TEXT"
type: "aws_proxy"
this is inline with AWS Documentation: enter link description here
Please, what am I missing?
At a glance I believe you have an error in your parameters block. If you include a $ref it discards anything in that block that follows it, so your proxy name is getting dropped. I have a similar setup with api-gateway proxying all calls to a lambda and this is my parameters block:
parameters:
- name: "proxy"
in: "path"
required: true
type: "string"
Additionally you may want an authorizer if you're at all worried about DDoS or serving up secure data. That's done by adding a security array as a sibling to parameters, and a securityDefinitions block as a sibling to paths
security:
- authorizer: []
securityDefinitions:
authorizer:
type : "apiKey"
name : "Authorization"
in : "header"
x-amazon-apigateway-authtype : "custom"
x-amazon-apigateway-authorizer : {
type : "request",
authorizerUri : "arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${region}:${account_id}:function:${authorizer_function_name}/invocations",
authorizerResultTtlInSeconds : 58,
identitySource: "method.request.header.authorization",
}
*note I'm publishing swagger as a terraform template, hence the ${} substitution.

AWS API Gateway caching ignores query parameters

I'm configuring the caching on AWS API Gateway side to improve performance of my REST API. The endpoint I'm trying to configure is using a query parameter. I already enabled caching on AWS API Gateway side but unfortunately had to find out that it's ignoring the query parameters when building the cache key.
For instance, when I make first GET call with query parameter "test1"
GET https://2kdslm234ds9.execute-api.us-east-1.amazonaws.com/api/test?search=test1
Response for this call is saved in cache, and when after that I make call another query parameter - "test2"
GET https://2kdslm234ds9.execute-api.us-east-1.amazonaws.com/api/test?search=test2
I get again response for first call.
Settings for caching are pretty simple and I didn't find something related to parameters configuration.
How can I configure Gateway caching to take into account query parameters?
You need to configure this option in the Gateway API panel.
Choose your API and click Resources.
Choose the method and see the
URL Query String session.
If there is no query string, add one.
Mark the "caching" option of the query string.
Perform the final tests and finally, deploy changes.
Screenshot
The following is how we can achieve this utilising SAM:
The end result in the AWS API Gateway console must display that the set caching checkbox is:
The *.yml template for the API Gateway would be:
Resources:
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
CacheClusterEnabled: true
CacheClusterSize: '0.5'
MethodSettings:
- HttpMethod: GET
CacheTtlInSeconds: 120
ResourcePath: "/getData"
CachingEnabled: true
DefinitionBody:
swagger: 2.0
basePath: /Prod
info:
title: OutService
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
paths:
"/getData":
get:
# ** Parameter(s) can be set here **
parameters:
- name: "path"
in: "query"
required: "false"
type: "string"
x-amazon-apigateway-integration:
# ** Key is cached **
cacheKeyParameters:
- method.request.querystring.path
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OutLambda.Arn}/invocations
responses: {}
EndpointConfiguration: PRIVATE
Cors:
AllowHeaders: "'*'"