API documentation for API Gateway with Lambda proxy integration - amazon-web-services

I defined a SAM app with few Lambdas behind an API Gateway"
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: !Ref EnvType
Auth:
DefaultAuthorizer: LambdaTokenAuthorizer
Authorizers:
LambdaTokenAuthorizer:
FunctionArn: !GetAtt AuthorizerLambda.Arn
MyFunction:
Type: 'AWS::Serverless::Function'
...
Events:
MyEvent:
Type: Api
Properties:
RestApiId: !Ref MyApi
Path: "/MyResource/{proxy+}"
Method: post
Obviously, API Gateway does not know much about the proxied resource such as:
proxied path(s)
request model
response model
Documentation generated from API Gateway stage reflects this:
swagger: "2.0"
info:
version: "1.0"
title: "xxx-dev"
host: "xxx.execute-api.us-west-2.amazonaws.com"
basePath: "/dev"
schemes:
- "https"
paths:
/MyResource/{proxy+}:
post:
responses: {}
security:
- LambdaTokenAuthorizer: []
securityDefinitions:
LambdaTokenAuthorizer:
type: "apiKey"
name: "Authorization"
in: "header"
x-amazon-apigateway-authtype: "custom"
Is there a way to feed API Gateway with missing bits (proxied paths, response models, request models)?
Ultimately i need a document that is good enough to generate the client code / allow some integration testing.
Similar question here -> Aws lambda proxy Swagger template integration

Related

Defining authorizer and using it in API Gateway using Open API

I am trying to define an authorizer and use it in a method using Open API Specification. For some reason the authorizer does not appear in the API Gateway Console after I deploy the template. Here's my template shortened:
Type: AWS::Serverless::Api
Properties:
Name: !Sub "API Gateway"
EndpointConfiguration:
Type: REGIONAL
DefinitionBody:
openapi: 3.0.3
info:
title: 'APIs'
version: 1.0.0
paths:
/callHistoryAsync:
post:
parameters:
- name: 'xxxxx'
in: 'query'
required: true
schema:
type: 'string'
x-amazon-apigateway-integration:
type: aws
requestParameters:
integration.request.header.X-Amz-Invocation-Type: '''Event'''
integration.request.querystring.store_id: "method.request.querystring.xxxxx"
httpMethod: POST
uri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Function.Arn}/invocations'
responses:
'202':
statusCode: '202'
selectionPattern: ""
responses:
'202':
description: successfully saved
security:
- Authorizer: []
components:
securitySchemes:
Authorizer:
type: 'request'
name: 'Authorization'
in: 'header'
x-amazon-apigateway-authorizer:
authorizerUri: !FindInMap [ !Ref StageName, !Ref "AWS::Region", AuthArn ]
identitySource: 'method.request.header.X-Authorization,method.request.header.X-Date'
type: 'request'
I defined the authorizer in components under securitySchemes and I am using it in the POST method specified under security.
But the authorizer does not appear in the console and neither does it appear under the method. What am I doing wrong?
I figured this out using the export property of the stage tab in API Gateway. I used an existing API Gateway that was defined using CloudFormation and exported it using Export as Swagger + API Gateway Extensions. This basically shows you all the syntax you want.
Here's the screenshot where is this option in the console.
From that export I could see that I need to change my securitySchemes to this:
components:
securitySchemes:
Authorizer:
type: "apiKey"
name: "Unused"
in: "header"
x-amazon-apigateway-authtype: "custom"
x-amazon-apigateway-authorizer:
authorizerUri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:xxxxxx:function:xxxxxxx/invocations"
authorizerResultTtlInSeconds: 300
identitySource: "method.request.header.Authorization, method.request.header.Date"
type: "request"

AWS Api gateway {proxy+} throws internal server error when 2 parent paths are added

I have a working lambda listening to HTTP API gateway with path /medication/{proxy+}. This workflow is working fine and is responding with expected result when {baseurl}/{basepath}/medication/{proxy+} is invoked. But in order to version the APIs, I decided to add a root path to this => /v1/medication/{proxy+}.
But on invoking {baseurl}/{basepath}/v1/medication/{proxy+} I am getting internal server error, with the same code(lambda) which was used before.
I have deployed both lambda and API gateway using sam/cloudformation template.
Below is the stripped-down template and swagger definitions:
swagger.yml
v1/medication/{proxy+}:
x-amazon-apigateway-any-method:
tags:
- "health"
summary: "Get medication details."
description: "Endpoint for fetching medication details"
operationId: "get allergy"
x-amazon-apigateway-integration:
uri: 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:{AWS:Region}:function:ucm-dfd-dev-DFDNotification/invocations'
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
httpMethod: "POST"
type: "aws_proxy"
security:
- dfd_authorizer: []
template.yml
DFDAllergy:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub '${AWS::StackName}-DFDAllergy'
Handler: controllers/allergy.handler
Runtime: nodejs12.x
CodeUri: src
Layers:
- !Ref DFDPackageLayer
Role: 'arn:aws:iam::{AWS:Region}:role/Lambda_Access_Role-Dev'
Events:
samapinew:
Type: Api
Properties:
RestApiId: !Ref DFDApi
Path: /v1/medication/{proxy+}
Method: ANY
Here the path in template.yml and endpoint in swagger.yml are only changes made to incorporate v1 as root path.
Cant seem to find out what I'm missing. Any help is appreciated. thanks in advance.

AWS SAM specify Method Request in API Gateway

I am fairly new to AWS SAM. I have implemented an API Gateway using AWS web console and specified the body validation in the API method request, I want to achieve the same thing but using SAM template. My search for how to specify Method Request in API Gateway SAM template gave nothing related to this. Any Help please?
Complete guide to add validations on API gateway here.
Below is a code snippet from SAM template.yaml to add body validations on a sample API. Here a PingInput API model is defined onthe /ping path on the API. The Model contains one required and one optional parameter. Calling the API without the required parameter will fail.
AuthApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
DefinitionBody:
swagger: '2.0'
info:
version: '1.0'
title: 'AwsRestServiceTemplate'
paths:
/ping:
x-amazon-apigateway-any-method:
responses: {}
post:
x-amazon-apigateway-request-validator: 'Validate body' # To specify that the Http Post body needs to be validated
parameters:
- in: 'body'
name: 'PingInput'
required: true
schema:
$ref: '#/definitions/PingInput'
x-amazon-apigateway-integration:
httpMethod: post
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PingFunction.Arn}/invocations
x-amazon-apigateway-request-validators:
Validate body:
validateRequestParameters: true
validateRequestBody: true
definitions:
PingInput:
type: 'object'
required:
- 'requiredKey'
properties:
requiredKey:
type: 'string'
optionalKey:
type: 'string'
If you are looking to configure `authorization", here is the SAM template.
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
DefaultAuthorizer: AWS_IAM
MyFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: MyFunction
...
Events:
Post:
Type: Api
Properties:
Path: /compute
Method: POST
RestApiId: !Ref MyApi
Auth:
Authorizer: AWS_IAM
You have to define the authorizer inside AWS::Serverless::Api definition and use it inside the function.
References:
https://github.com/awslabs/serverless-application-model/blob/master/examples/2016-10-31/api_aws_iam_auth/template.yaml
https://github.com/awslabs/serverless-application-model/blob/master/examples/2016-10-31/api_cognito_auth/template.yaml

AWS SAM Template Fails to Create Configurations for API Gateway

I have a problem with AWS SAM and provisioning API Gateway configurations. I am trying to do a few things:
Configure the API gateway to require api-key in the headers
Create my own stage as defined in my config files.
The API gateway model defined in my file is not being created
Currently, the API gateway gets provisioned and linked to my lambda function but it fails in the two requirements above. Below are my files: template.yaml and swagger.yaml.
Template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-nfeed-s3
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 60
Api:
EndpointConfiguration: REGIONAL
Resources:
SAMnfeedS3API:
Type: AWS::Serverless::Api
Properties:
StageName: alpha
DefinitionUri: ./swagger.yaml
Resources:
SAMnfeedS3Lambda:
Type: AWS::Serverless::Function
Properties:
CodeUri: test-function-sam/
Handler: nfeed_vdp_clusters.lambda_handler
Runtime: python3.6
Role: arn:aws:iam::XXXXXXX:role/Lambda
Events:
SAMnfeedS3API:
Type: Api
Properties:
Path: /vdp_clusters
Method: GET
Environment:
Variables:
TEST: test
Outputs:
SAMnfeedS3API:
Description: "API Gateway endpoint URL for Staging env"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Staging/vdp_clusters"
SAMnfeedS3Lambda:
Description: "Lambda Function ARN"
Value: !GetAtt SAMnfeedS3Lambda.Arn
Swagger.yaml
---
swagger: '2.0'
info:
title: !Ref AWS::StackName
basePath: "/alpha"
schemes:
- "https"
x-amazon-apigateway-api-key-source : "HEADER"
paths:
"/vdp_clusters":
get:
consumes:
- application/json
produces:
- application/json
parameters:
- name: x-api-key
in: header
required: true
type: string
responses:
200:
description: "200 response"
schema:
$ref: "#/definitions/Empty"
x-amazon-apigateway-integration:
uri: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:XXXXXXXXX:function:${SAMnfeedS3Lambda.Arn}/invocations
responses:
default:
statusCode: "200"
httpMethod: "POST"
type: aws_proxy
security:
- api_key: []
securityDefinitions:
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
definitions:
Empty:
type: "object"
title: "Empty Schema"
$schema: "http://json-schema.org/draft-04/schema#"
As defined in my swagger and template files, "alpha" stage should be created for the gateway but nothing appears. The "Empty" model and api-key requirement also do not appear. Any help, would be appreciated.
The problem is you have duplicated the Resources key in the template.
I recommend always using the yamllint utility on your SAM templates, because it detects YAML formatting issues that sam validate can't always detect. Here is what I got:
▶ yamllint sam-app/template.yaml
sam-app/template.yaml
...
18:1 error duplication of key "Resources" in mapping (key-duplicates)
If you then look in the packaged.yml file that is created by the sam build step, you'll notice that the API you defined will be missing. That's because it's impossible for a dict in Python to contain duplicate keys. The second Resources block you specified just overwrites the first one when the Python YAML library reads the file in.
SAM then generates the implicit API SAMnfeedS3API based on the API you specified in Events using its own generated Swagger rather than the one you (thought you) provided.
Note also that, after you fix up the duplicate key issue, you will also need to reference your API from the Events with a line like:
Events:
SAMnfeedS3API:
Type: Api
Properties:
Path: /vdp_clusters
Method: GET
RestApiId: !Ref SAMnfeedS3API ## ADD THIS LINE
See also my earlier answer here.

not a valid key=value pair (missing equal-sign) in Authorization header

While hitting an API from Postman I am getting this error.
API details:
URL:
https://account-perf.myglobal.com/v1/users/00uk0khprrME7gZOU0h7/credentials/change_password
Header:
Content-Type:application/json Authorization:Bearer
n7mbkw74jsubd7rauhptdnre
Type:
POST
Body:
{"password":"Baddy125#","token":"eyJhbGci...."}
Edit 1:
Web-service call to generate token-
URL-
https://api-perf.myglobal.com/rest/oauth2/v1/token
Type-
POST
Body-
client_id:abcd client_secret:xyz grant_type:client_credentials
I had this whenever any unhandled endpoint method or resource was called. My setup is an API Gateway with defined resources (e.g. /myendpoint) and defined methods for those endpoints (e.g. GET).
To fix it, I created a Node.js Lambda function that just returned a 404. Then I added any ANY method at the root of the endpoints / and pointed it as a Lambda proxy function to the ANY methods.
Then I added a proxy resource, e.g. /{proxy} -- there's a checkbox you can click when creating a resource to tell it to proxy. An ANY method on that resource pointing to the same Lambda function, deploy the API, and I'm done.
Now instead of the auth bearer token error, I get a proper HTTP 404 error.
#Matt H - That's pretty good idea this gave me an inspiration of another one.
Assuming all of the other paths within the API are explicitly specified, I created a default path /{proxy+} which would return a http 404, message resource not found. Instead of using lambda, I was able to create a mock response, so there isn't even any cost incurred for getting Lambda to return the response.
I created my APIs via Open API spec. This is how my YAML for the implementation would like
/{proxy+}:
x-amazon-apigateway-any-method:
responses:
404:
description: "404 response"
content: {}
x-amazon-apigateway-integration:
responses:
404:
statusCode: "404"
responseTemplates:
application/json: "{\"message\":\"resource not available\"}"
requestTemplates:
application/json: "{\"statusCode\": 404}"
passthroughBehavior: "when_no_templates"
type: "mock"
Serverless also has the ability to specify inline mock response. Below can be a sample:
functions:
default:
handler: handler.default
events:
- http:
path: hello
cors: true
method: get
integration: mock
request:
template:
application/json: '{"statusCode": 404}'
response:
template: $input.path('$')
statusCodes:
404:
pattern: '' #default method
template:
application/json: '{"statusCode": 404, "message":"resource not found"}'
serverless doc: https://www.serverless.com/framework/docs/providers/aws/events/apigateway/#custom-response-templates
Analyze and validate the request path, in case the request is incorrect this error is thrown at API Gateway. I stepped on the same error, when corrected the request parameters it worked well.
Let me know.
I managed to do it by proxying the ANY /{proxy+} route to a lambda which will always respond with an HTTP 404
Since all other routes are precisely configured, this ANY /{proxy+} route acts as the default one and will catch any unmatched request
Here is how I did it with CloudFormation :
Parameters:
RestAPI:
Type: String
RestApiRootResourceId:
Type: String
LambdaName:
Type: String
Path:
Type: String
RootResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref RestAPI
ParentId: !Ref RestApiRootResourceId
PathPart: !Ref Path
ProxyResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref RestAPI
ParentId: !Ref RestApiRootResourceId
PathPart: "{proxy+}"
AnyMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
RestApiId: !Ref RestAPI
ResourceId: !Ref ProxyResource
HttpMethod: ANY
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
PassthroughBehavior: WHEN_NO_MATCH
Uri:
Fn::Join:
- ":"
- - !Sub "arn:aws:apigateway:${AWS::Region}:lambda"
- !Sub "path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function"
- !Sub "${LambdaName}/invocations"
ApiGatewayInvokeLambdaPermissionAny:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName:
Fn::Join:
- ":"
- - !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function"
- !Ref LambdaName
Principal: apigateway.amazonaws.com
SourceArn:
Fn::Join:
- ":"
- - !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}"
- !Sub "${RestAPI}/*/ANY/*"
Paramters :
RestAPI is your API ID
RestApiRootResourceId is the ID of the root resource (!GetAtt "RestApi.RootResourceId")
LambdaName is the name of your proxy lambda
Path is something I have bewteen the stage and the root (for mty specific usage)