Related
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
}
}
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.
I am using AWS API Gateway to consume an image file to send to a Lambda function. The POST reaches my Lambda function just fine, with the binary data transformed into a base64 string, but when I try to decode that base64 string and save it as an image, the image cannot be decoded. In fact, the string returned after transformation is smaller than the image itself, which makes me think that something is going wrong. I have tried simply returning the string provided to the Lambda function as the response and decoding that locally, which doesn't work either.
Here is the configuration for my API Gateway method:
"/photo/{photo_id}": {
"x-amazon-apigateway-any-method": {
"consumes": [
"image/jpeg",
"image/jpg"
],
"produces": [
"application/json",
"image/jpg"
],
"parameters": [
{
"name": "Content-Type",
"in": "header",
"required": false,
"type": "string"
},
{
"name": "Accept",
"in": "header",
"required": false,
"type": "string"
},
{
"name": "photo_id",
"in": "path",
"required": true,
"type": "string"
},
{
"in": "body",
"name": "Empty",
"required": true,
"schema": {
"$ref": "#/definitions/Empty"
}
},
{
"in": "body",
"name": "Empty",
"required": true,
"schema": {
"$ref": "#/definitions/Empty"
}
}
],
"responses": {
"200": {
"description": "200 response",
"schema": {
"$ref": "#/definitions/Empty"
}
},
"500": {
"description": "500 response"
}
},
"x-amazon-apigateway-integration": {
"credentials": "redacted",
"uri": "redacted",
"responses": {
"default": {
"statusCode": "200"
},
".*Error.*": {
"statusCode": "500"
}
},
"requestParameters": {
"integration.request.header.Accept": "method.request.header.Accept",
"integration.request.header.Content-Type": "method.request.header.Content-Type"
},
"requestTemplates": {
"image/jpeg": "{\"photo\": \"$input.body\", \"photo_id\": \"$input.params('photo_id')\", \"app_id\": \"$input.params('x-app-id')\", \"httpMethod\": \"$context.httpMethod\"}",
"image/jpg": "{\"photo\": \"$input.body\", \"photo_id\": \"$input.params('photo_id')\", \"app_id\": \"$input.params('x-app-id')\", \"httpMethod\": \"$context.httpMethod\"}"
},
"passthroughBehavior": "when_no_templates",
"httpMethod": "POST",
"contentHandling": "CONVERT_TO_TEXT",
"type": "aws"
}
}
}
And the simple Lambda function to return the string back:
def lambda_handler(event, context):
photo_string = event['photo']
return photo_string
The cURL command I'm using to test the implementation:
curl -X POST https://execute-api.eu-central-1.amazonaws.com/prod/photo/new -H "Content-Type: image/jpg" -H "x-app-id:test" -d #IMG_1642.jpg
Any idea why the base64 that is returned would be different?
I figured it out, I needed to be using --data-binary in my cURL invocation instead of just -d which is an alias for --data-ascii. It works fine now.
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.
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"
}
}
}