AWS API Gateway - HTTP Passthrough Path Parameters - amazon-web-services

I'm trying out the HTTP passthrough functionality in API gateway, passing through a resource method to another API. I want to pass through the path parameters from the API gateway URL to the backend API that also needs those path parameters.
I have the following simple Swagger document trying to test this out:
{
"swagger": "2.0",
"info": {
"version": "2017-09-15T03:33:48Z",
"title": "api-gateway-http-test"
},
"schemes": [
"https"
],
"paths": {
"/subresource/{name}": {
"get": {
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-integration": {
"uri": "http://my.web.service.url/subresource/{name}",
"passthroughBehavior": "when_no_match",
"httpMethod": "GET",
"type": "http_proxy",
"requestParameters": {
"integration.request.path.name": "method.request.path.name"
}
}
}
}
},
"definitions": {
"Empty": {
"type": "object",
"title": "Empty Schema"
}
}
}
When I try deploying this to API Gateway via CloudFormation, API Gateway gives me this error:
Unable to put integration on 'GET' for resource at path '/subresource/{name}':
Invalid mapping expression specified:
Validation Result:
warnings : [], errors : [Invalid mapping expression parameter specified: method.request.path.name]
I've looked at various sources online, and this way of configuring the "requestParameters" section seems to be the recommended way to pass through path parameters to the backend API.
What am I missing here that would cause this to not work?

It is missing parameter definitions.
Check it out with the below,
{
"swagger": "2.0",
"info": {
"version": "2017-09-15T03:33:48Z",
"title": "api-gateway-http-test"
},
"schemes": [
"https"
],
"paths": {
"/subresource/{name}": {
"get": {
"produces": [
"application/json"
],
"parameters": [
{
"name": "name",
"in": "path",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-integration": {
"uri": "http://google.com/subresource/{name}",
"passthroughBehavior": "when_no_match",
"httpMethod": "GET",
"type": "http_proxy",
"requestParameters": {
"integration.request.path.name": "method.request.path.name"
}
}
}
}
},
"definitions": {
"Empty": {
"type": "object",
"title": "Empty Schema"
}
}
}

Related

AWS API Gateway fails to import Swagger definition: Unsupported model type 'MapProperty'

I am currently on this screen trying to import my app's swagger definition so I can create an API Gateway instance.
Unfortunately, you can see I'm getting some errors - even though swagger seems to think it's entirely fine.
Your API was not imported due to errors in the Swagger file.
Unable to create model for 200 response to method 'GET /api/v1/courses': Validation Result: warnings : [], errors : [Invalid content type specified: */*]
Unsupported model type 'MapProperty' in 200 response to method 'GET /api/v1/courses/all'. Ignoring.
Here is my swagger definition:
{
"swagger": "2.0",
"info": {
"description": "Api Documentation",
"version": "1.0",
"title": "Api Documentation",
"termsOfService": "urn:tos",
"contact": {},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0"
}
},
"host": "********.appspot.com",
"basePath": "/",
"tags": [{
"name": "course-controller",
"description": "Course Controller"
}],
"paths": {
"/api/v1/courses": {
"get": {
"tags": ["course-controller"],
"summary": "getCourses",
"operationId": "getCoursesUsingGET",
"produces": ["*/*"],
"parameters": [{
"name": "code",
"in": "query",
"description": "code",
"required": false,
"type": "string"
}],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/Course"
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
},
"deprecated": false
}
},
"/api/v1/courses/all": {
"get": {
"tags": ["course-controller"],
"summary": "getAllCourses",
"operationId": "getAllCoursesUsingGET",
"produces": ["*/*"],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": {
"type": "object"
}
}
},
"401": {
"description": "Unauthorized"
},
"403": {
"description": "Forbidden"
},
"404": {
"description": "Not Found"
}
},
"deprecated": false
}
}
},
"definitions": {
"Course": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"credits": {
"type": "integer",
"format": "int32"
},
"id": {
"type": "integer",
"format": "int32"
},
"lastUpdated": {
"type": "string"
},
"name": {
"type": "string"
},
"prerequisites": {
"type": "string"
},
"restrictions": {
"type": "string"
},
"seats": {
"$ref": "#/definitions/Seats"
},
"waitlist": {
"$ref": "#/definitions/Seats"
}
},
"title": "Course"
},
"Seats": {
"type": "object",
"properties": {
"actual": {
"type": "integer",
"format": "int32"
},
"capacity": {
"type": "integer",
"format": "int32"
},
"remaining": {
"type": "integer",
"format": "int32"
}
},
"title": "Seats"
}
}
}
Is there any reason you can find for this swagger definition breaking in API Gateway?
AWS API Gateway has some limitations in its OpenAPI support. For example, it does not support additionalProperties in models (this keyword is used in the 200 response schema for the /api/v1/courses/all endpoint in your API).
You can click the "Import and ignore warnings" button to ignore those errors and proceed with the import.

How to enable CORS configuration in WSO2 for a specific API by using REST API?

I am creating and publishing APIs using WSO2 REST APIs and not from its UI because i have hundreds of WSO2 APIs to manage. I use swagger file(in json format) to configure all the details about my API and then publish this swagger file using curl command. I want to enable CORS configuration for my WSO2 APIs.
The documentation provided for WSO2 APIs provides information only about enabling CORS config via UI. Here is the link.
I could not find any info as to how i can enable it by any means other than directly from its UI. I have tried adding the following field in the API's swagger file but this change is not reflected in the published API.
"CORSConfiguration": {
"Enabled": "true",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS",
"Access-Control-Allow-Headers": "authorization,Access-Control-Allow-Origin,Content-Type,SOAPAction",
"Access-Control-Allow-Credentials": "false"
}
Any help to enable the CORS configuration for a particular API will be appreciated. Thanks :)
CORS information should go in the API create/update payload like this.
"corsConfiguration": {
"accessControlAllowOrigins": ["*"],
"accessControlAllowHeaders": [
"authorization",
"Access-Control-Allow-Origin",
"Content-Type",
"SOAPAction"
],
"accessControlAllowMethods": [
"GET",
"PUT",
"POST",
"DELETE",
"PATCH",
"OPTIONS"
],
"accessControlAllowCredentials": false,
"corsConfigurationEnabled": false
}
See the sample payload in [1].
[1] https://docs.wso2.com/display/AM260/apidocs/publisher/#!/operations#APIIndividual#apisPost
#Bee, here is what i tried to do.
{
"swagger": "2.0",
"info": {
"description": "Registration Type Master",
"version": "1.0",
"title": "Test_Entity_Master_API",
"termsOfService": "urn:tos",
"contact": {"name":"RD"},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0"
}
},
"host": "http://sampleurl.com/",
"basePath": "/samplemethod",
"schemes": [
"http"
],
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"paths": {
"/regtype/createregtype": {
"post": {
"summary": "Create reg type entry",
"tags": [
"Registration Type Master"
],
"deprecated": false,
"produces": [
"application/json"
],
"parameters": [
{
"name": "Body",
"in": "body",
"required": true,
"description": "",
"schema": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
}
}
],
"responses": {
"200": {
"description": "",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean"
},
"error": {
"type": "boolean",
"default": false
},
"message": {
"type": "string"
},
"data": {
"type": "object"
}
}
}
},
"500": {
"description": "",
"schema": {
"type": "object",
"properties": {
"success": {
"type": "boolean",
"default": false
},
"error": {
"type": "boolean"
},
"message": {
"type": "string"
},
"data": {
"type": "object"
}
}
}
}
}
}
}
},
"tags": [
{
"name": "entity-master-controller",
"description": "Entity Master Controller"
}
],
"corsConfiguration": {
"accessControlAllowOrigins": ["https://dtdevsso.ril.com"],
"accessControlAllowHeaders":[
"authorization",
"Access-Control-Allow-Origin",
"Content-Type",
"SOAPAction"
],
"accessControlAllowMethods":[
"GET",
"PUT",
"POST",
"DELETE",
"PATCH",
"OPTIONS"
],
"accessControlAllowCredentials": "true",
"corsConfigurationEnabled": "true"
}
}
In this swagger file, inspite of adding the CORS payload, it is not reflected after publishing the API through the swagger file.
To setup CORS support you must first define an OPTIONS method in your resource that returns the required headers.
All paths in swagger need a cors option chunk. this is the chunk.
"/users":
{
"options": {
"summary": "CORS support",
"description": "Enable CORS by returning correct headers\n",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"CORS"
],
"x-amazon-apigateway-integration": {
"type": "mock",
"requestTemplates": {
"application/json": "{\n \"statusCode\" : 200\n}\n"
},
"responses": {
"default": {
"statusCode": "200",
"responseParameters": {
"method.response.header.Access-Control-Allow-Headers": "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'",
"method.response.header.Access-Control-Allow-Methods": "'*'",
"method.response.header.Access-Control-Allow-Origin": "'*'"
},
"responseTemplates": {
"application/json": "{}\n"
}
}
}
},
"responses": {
"200": {
"description": "Default response for CORS method",
"headers": {
"Access-Control-Allow-Headers": {
"type": "string"
},
"Access-Control-Allow-Methods": {
"type": "string"
},
"Access-Control-Allow-Origin": {
"type": "string"
}
}
}
}
}
}
For more details you can visit this link
I used the following payload for creating/updating an API in WSO2.
It is working perfectly. Sorry for the delayed update on this.
{
"name": "%apiName%",
"description": "%apiDescription%",
"context": "/%apiName%",
"version": "%apiVersion%",
"provider": "%apiProvider%",
"apiDefinition": "%swaggger_extended.json% // Input swagger file",
"wsdlUri": null,
"status": "CREATED",
"responseCaching": "Disabled",
"cacheTimeout": 300,
"destinationStatsEnabled": false,
"isDefaultVersion": false,
"type": "HTTP",
"transport": [
"http",
"https"
],
"tags": ["%apiTags%"],
"tiers": ["%apiTiersCollection%"],
"visibility": "%apiVisibility%",
"visibleRoles": [],
"endpointConfig": "%endPointConfig%",
"gatewayEnvironments": "Production and Sandbox",
"subscriptionAvailability": null,
"subscriptionAvailableTenants": [],
"businessInformation": {
"businessOwnerEmail": "%BizOwnerName#ril.com%",
"technicalOwnerEmail": "%TechOwnerName#ril.com%",
"technicalOwner": "%TechOwnerName%",
"businessOwner": "%BizOwnerName%"
},
"corsConfiguration": {
"accessControlAllowOrigins": ["originURL"],
"accessControlAllowHeaders": [
"authorization",
"Access-Control-Allow-Origin",
"Content-Type",
"SOAPAction"
],
"accessControlAllowMethods": [
"GET",
"PUT",
"POST",
"DELETE",
"PATCH",
"OPTIONS"
],
"accessControlAllowCredentials": false,
"corsConfigurationEnabled": true
}
}

AWS APIGateway CloudFormation specify Api Key required for method?

I have the below CloudFormation template which creates my API Gateway (backed by Lambda). I want to enable API Keys as a requirement for one or more of these methods. I have successfully created API Keys, Usage Plans and the association between the two, but can't figure out how to actually enable the 'requires API Key' property for some of the methods. The documentation from AWS specifies an 'ApiKeyRequired' property as a part of the AWS::ApiGateway::Method component, but my CF template doesn't have or use this component? I'm unsure how to use it considering I've never required it before?
My template is below:
"ServerlessRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"Properties": {
"Description":"This is a placeholder for the description of this web api",
"ApiKeySourceType":"HEADER",
"Body": {
"info": {
"version": "1.0",
"title": {
"Ref": "AWS::StackName"
}
},
"paths": {
"/list/tables": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableList.Arn}/invocations"
}
},
"security": [
{
"api_key": []
}
],
"responses": {}
}
},
"/list/columns/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetColumnList.Arn}/invocations"
}
},
"responses": {}
}
},
"datagw/general/table/get/{tableid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableResponse.Arn}/invocations"
}
},
"responses": {}
}
},
"/": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${Get.Arn}/invocations"
}
},
"responses": {}
}
},
"/tables/{tableid}/{columnid}": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetTableBasic.Arn}/invocations"
}
},
"responses": {}
}
},
"securityDefinitions": {
"type": "api_key",
"name": "x-api-key",
"in": "header"
}
},
"swagger": "2.0"
}
}
},
I think adding security under each path and then securityDefinitions under paths would work.
"paths": {
"/list/tables": {
"get": {
"x-amazon-apigateway-integration": {
"httpMethod": "POST",
"type": "aws_proxy",
"uri": {
"Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-
03-31/functions/${GetTableList.Arn}/invocations"
}
},
"security": [
{
"api_key": []
}
]
}
}
},
"securityDefinitions": {
"type": "api_key",
"name": "x-api-key",
"in": "header"
}
I ran into the same issue and resolved it by abandoning the use of the Body property in the AWS::ApiGateway::RestApi using:
"ServerlessRestApi": {
"Type": "AWS::ApiGateway::RestApi",
"DependsOn": "AspNetCoreFunction",
"Properties": {
"Description":"My Api Gateway",
"ApiKeySourceType" : "HEADER",
"EndpointConfiguration" : { "Types" : [ "REGIONAL" ]}
}
},
Then, I created a proxy resource. In your case, you would create a resource for each of your paths. Where I have, "{proxy+}", you would have "/list/tables."
"ProxyResource": {
"Type": "AWS::ApiGateway::Resource",
"Properties": {
"RestApiId": {
"Ref": "ServerlessRestApi"
},
"ParentId": {
"Fn::GetAtt": [
"ServerlessRestApi",
"RootResourceId"
]
},
"PathPart": "{proxy+}"
}
},
Finally, I was able to define an AWS::ApiGateway::Method then enforce usage an API key:
"CoreApiPostMethod":
{
"Type": "AWS::ApiGateway::Method",
"DependsOn" : ["AspNetCoreFunction", "ServerlessRestApi"],
"Properties":
{
"AuthorizationType" :"NONE",
"OperationName" : "My API Post Request",
"ApiKeyRequired" : true,
"ResourceId": { "Ref": "ProxyResource" },
"RestApiId": {
"Ref": "ServerlessRestApi"
},
"HttpMethod" : "POST",
"Integration" : {
"ConnectionType" : "INTERNET",
"IntegrationHttpMethod" : "POST",
"Type" : "AWS_PROXY",
"Uri" : {
"Fn::Sub":"arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AspNetCoreFunction.Arn}/invocations"
}
}
}
},
And then follow the same pattern for the other HTTP methods. It's more verbose than the original configuration, but it does give you more control over the method configuration.
Late to the party.
"x-amazon-apigateway-api-key-source" : "HEADER",
And
"securityDefinitions": {
"<SOME_NAME>": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
}
}
And
"security" : [{
"<SOME_NAME>" : []
}]
So a possible working solution could be
"Body": {
"swagger": "2.0",
"info": {
"version": "2017-01-27T21:44:58Z",
"title": {"Ref": "AWS::StackName"}
},
"basePath": "/bbd",
"x-amazon-apigateway-api-key-source" : "HEADER",
"schemes": [
"https"
],
"paths": {
"/{proxy+}": {
"x-amazon-apigateway-any-method": {
"produces": [
"application/json"
],
"parameters": [
{
"name": "proxy",
"in": "path",
"required": true,
"type": "string"
}
],
"security" : [{
"bbd" : []
}],
"responses": {},
"x-amazon-apigateway-integration": {
"responses": {
"default": {
"statusCode": "200"
}
},
"uri": "<URL>",
"passthroughBehavior": "when_no_match",
"httpMethod": "POST",
"cacheNamespace": "xh7gp9",
"cacheKeyParameters": [
"method.request.path.proxy"
],
"contentHandling": "CONVERT_TO_TEXT",
"type": "aws_proxy"
}
}
}
},
"securityDefinitions": {
"bbd": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
}
}
}
Complete guide here. This guide provides a basic setup for enabling API keys for any API Gateway methods.
Use AWS::Serverless::Api for defining your API. It supports an Auth attribute which has an attribute named ApiKeyRequired. Set this to true.
Following code snippet from the above guide should do.
AuthApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
ApiKeyRequired: 'true' # This makes passing ApiKey mandatory
DefinitionBody:
swagger: '2.0'
info: ...
"security" : [{
"myKey" : []
}],
"myKey": {
"type": "apiKey",
"name": "x-api-key",
"in": "header"
},
Adding security element in body and myKey element in securityDefinitions worked for me.

Validating request path parameter of AWS API gateway?

Let's say I have an api with paths / and /{pets} and /{pets}/pet. Now I'm trying to validate the path {pets} parameter so that only path having alphanumerical characters of length 6 will be validated and processed to the backend lambda all others will be rejected. I tried the following swagger schema specifying format and type for the parameter. I even tried using pattern in the schema but it seems to be not working. May I know how can we limit only path parameters of certain IDs.
{
......
"/{pets}/pet": {
"get": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"parameters": [{
"name": "pets",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "[A-Za-z0-9]{6}"
}
}],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-request-validator": "Validate query string parameters and headers",
"x-amazon-apigateway-integration": {
"responses": {
"default": {
"statusCode": "200"
}
},
"requestTemplates": {
"application/json": "## See ...."
},
"uri": "........",
"passthroughBehavior": "when_no_templates",
"httpMethod": "POST",
"contentHandling": "CONVERT_TO_TEXT",
"type": "aws"
}
}
}
.....
}
What I'm trying to achieve:
https://api.example.com/aacc77/pet -- Accept
https://api.example.com/aacc77s/pet -- Reject
https://api.example.com/aacc7/pet -- Reject
https://api.example.com/aacc_7/pet -- Reject
Basically, I want to use this regex pattern for the path [A-Za-z0-9]{6}.
"pets": {
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Pets Schema",
"type": "string",
"pattern": "[A-Za-z0-9]{6}"
}
I see that there is a related question here, I wonder whether there is a solution available for this.

Unable to execute Lambda in Async mode via API Gateway POST request

Why currently there no way to execute AWS Lambda in asynchronous mode via Gateway API without involving intermediary Lambda just for calling invoke() method?
Even if i add integration like this:
r = client.put_integration(
restApiId=rest_api_id,
resourceId=resource_id,
httpMethod='POST',
type='AWS',
integrationHttpMethod='POST',
uri=uri,
requestParameters={
'integration.request.header.X-Amz-Invocation-Type': "'Event'",
'integration.request.header.Invocation-Type': "'Event'"
}
)
It still executed synchronously...
Are there some platform limitation or so?
I have an example Swagger document which you can switch invocation type to Lambda function. I guess you already got how to map the header to trigger the different invocation types, but I think you might forget to deploy the API.
Swagger
{
"swagger": "2.0",
"info": {
"version": "2016-02-11T22:00:31Z",
"title": "LambdaAsync"
},
"host": "<placeholder>",
"basePath": "<placeholder>",
"schemes": [
"https"
],
"paths": {
"/": {
"get": {
"produces": [
"application/json"
],
"parameters": [
{
"name": "X-Amz-Invocation-Type",
"in": "header",
"required": false,
"type": "string"
}
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
}
},
"x-amazon-apigateway-integration": {
"passthroughBehavior": "when_no_match",
"httpMethod": "POST",
"uri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:<account>:function:<function_name>/invocations?Qualifier=$LATEST",
"responses": {
"default": {
"statusCode": "200"
}
},
"requestParameters": {
"integration.request.header.X-Amz-Invocation-Type": "method.request.header.X-Amz-Invocation-Type"
},
"type": "aws"
}
}
}
},
"definitions": {
"Empty": {
"type": "object",
"title": "Empty Schema"
}
}
}