I have created a Rest API that works as a proxy to a public URL. I have set the cache and noticed I have to configure the cacheKeyParameters for AWS to create the keys for caching.
I do not know beforehand what would be the query strings that the request may have. It could have myapi?type=1 myapi?search=terrain or anything. I'm looking for a wildcard to be used here. How could I configure my proxy?
Here is my API definition:
openapi: 3.0.1
info:
description: API as a proxy to public url
version: 1.0.0
paths:
"/{proxy+}":
x-amazon-apigateway-any-method:
parameters:
- name: proxy
in: path
required: true
schema:
type: string
responses: {}
x-amazon-apigateway-integration:
cacheKeyParameters:
- method.request.path.proxy
- method.request.querystring.query # Here I need a wildcard for every query string
responses:
default:
statusCode: '200'
requestParameters:
integration.request.path.proxy: method.request.path.proxy
uri:
Fn::FindInMap : [EnvMap, Ref: Env, proxyUrl]
passthroughBehavior: when_no_match
httpMethod: ANY
type: http_proxy
Related
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"
I use AWS ECS for my server (multiple microservers) in some website, and I use API Gateway + OpenApi to define the routes and to integrate them with the ECS microservers.
Every path prefix should integrate with different ECS and direct all subpaths to there.
Is there a way to use some regex in OpenApi to integrate it with ALL paths and operations under some path?
This is how I'm defining the path for single path and single operation:
OpenApi:
openapi: "3.0.1"
info:
title:
Fn::Sub: "${EnvironmentName}-api"
version: 0.0.1
paths:
/api/project:
get:
responses:
default:
description: "Default response for GET"
x-amazon-apigateway-integration:
payloadFormatVersion: "1.0"
connectionId:
Fn::ImportValue:
Fn::Sub: ${EnvironmentName}:HttpApiVPCLink
type: "http_proxy"
httpMethod: "ANY"
uri:
Fn::ImportValue:
Fn::Sub: ${EnvironmentName}:DiscoveryService-microserver-1
connectionType: "VPC_LINK"
/api/item:
get:
responses:
default:
description: "Default response for GET"
x-amazon-apigateway-integration:
payloadFormatVersion: "1.0"
connectionId:
Fn::ImportValue:
Fn::Sub: ${EnvironmentName}:HttpApiVPCLink
type: "http_proxy"
httpMethod: "ANY"
uri:
Fn::ImportValue:
Fn::Sub: ${EnvironmentName}:DiscoveryService-microserver-2
connectionType: "VPC_LINK"
So in this code:
Route /api/project with operation get will use microserver1 and
Route /api/item with operation get will use microserver2
But what I need is every route with prefix /api/project and any operation will use microserver1,
for example - post operation or route /api/project/{id} should also use the microserver1 without additional definition in the OpenApi file
Is there any way to define something like that?
Use the proxy integration. See Documentations
When you use the proxy integration, your all sub API will be proxied to the targets.
I've created an API on AWS API Gateway. I've used this to proxy to a static app, e.g. called sample-app, that I've deployed to netlify.
The openapi configuration for it is attached below.
https://sample.com/apps/sample-app/ works fine and I can see the app that I had deployed to netlify.
https://sample.com/apps/sample-app gives me a blank page. On the console, it shows an error message: net::ERR_ABORTED 404
My questions are:
Why does this not work?
How can I get API Gateway to just add the /?
Or, are there any better alternatives?
openapi: "3.0.1"
info:
title: "sample-api"
version: "2020-04-29T23:24:23Z"
servers:
- url: "https://sample.com"
paths:
/apps/sample-app/{proxy+}:
x-amazon-apigateway-any-method:
parameters:
- name: "proxy"
in: "path"
required: true
schema:
type: "string"
x-amazon-apigateway-integration:
uri: "https://sample-app.netlify.app/{proxy}"
responses:
default:
statusCode: "200"
requestParameters:
integration.request.path.proxy: "method.request.path.proxy"
passthroughBehavior: "when_no_match"
httpMethod: "ANY"
cacheNamespace: "2ns27y"
cacheKeyParameters:
- "method.request.path.proxy"
type: "http_proxy"
/apps/sample-app:
x-amazon-apigateway-any-method:
responses:
"200":
description: "200 response"
content:
application/json:
schema:
$ref: "#/components/schemas/Empty"
x-amazon-apigateway-integration:
uri: "https://sample-app.netlify.app/"
responses:
default:
statusCode: "200"
passthroughBehavior: "when_no_match"
httpMethod: "ANY"
type: "http_proxy"
I'm using AWS Serverless to create an API Gateway backed with Lambda functions.
I have the following resources and methods defined:
/projects
-> GET (should require API key)
-> OPTIONS (should not, since it is used for CORS preflight)
I'm having issues with CORS and requiring an API key. The frontend client code is getting a 403 Forbidden error when it initiates the preflight CORS OPTIONS request, since the API Key Required in the AWS Management console is set to True for the OPTIONS method.
I want to disable security specifically for the OPTIONS request, but keep it for all other methods (GET, POST, etc.). Here are my resource definitions (you can see I have set a default ApiKeyRequired: true in my Auth object:
MyApi:
Type: 'AWS::Serverless::Api'
Name: MyApi
Properties:
Auth:
AddDefaultAuthorizerToCorsPreflight: true
ApiKeyRequired: true # sets for all methods
Cors:
AllowCredentials: true
AllowHeaders: '"Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token"'
AllowMethods: '"POST,GET,OPTION"'
AllowOrigin: '"*"'
MaxAge: '"600"'
StageName: !Ref StageName
DefinitionBody:
swagger: 2.0
info:
title: !Sub API-Lambda-${StageName}
description: "API for MyApi"
version: "1.0.0"
paths:
/projects:
get:
produces:
- application/json
responses:
"200":
description: OK
x-amazon-apigateway-any-method:
produces:
- application/json
x-amazon-apigateway-integration:
httpMethod: post
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetAllProjectsFunction.Arn}/invocations
options:
consumes:
- application/json
produces:
- application/json
responses:
'200':
description: 200 response
headers:
Access-Control-Allow-Origin:
type: string
Access-Control-Allow-Methods:
type: string
Access-Control-Allow-Headers:
type: string
x-amazon-apigateway-integration:
responses:
default:
statusCode: 200
responseParameters:
method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,mode,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
method.response.header.Access-Control-Allow-Origin: "'*'"
passthroughBehavior: when_no_match
requestTemplates:
application/json: "{\"statusCode\": 200}"
type: mock
/projects/{userId}:
get:
responses:
"200":
description: OK
x-amazon-apigateway-any-method:
produces:
- application/json
x-amazon-apigateway-integration:
httpMethod: post
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GetProjectsForUserFunction.Arn}/invocations
options:
consumes:
- application/json
responses:
'200':
description: 200 response
headers:
Access-Control-Allow-Origin:
type: string
Access-Control-Allow-Methods:
type: string
Access-Control-Allow-Headers:
type: string
x-amazon-apigateway-integration:
responses:
default:
statusCode: 200
responseParameters:
method.response.header.Access-Control-Allow-Methods: "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'"
method.response.header.Access-Control-Allow-Headers: "'Content-Type,mode,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'"
method.response.header.Access-Control-Allow-Origin: "'*'"
passthroughBehavior: when_no_match
requestTemplates:
application/json: "{\"statusCode\": 200}"
type: mock
I know that the Swagger documentation says I can override security by adding a security object for each resource method. This SO post also suggests I can disable security by making the security object an empty list.
However, I tried the following approaches:
options:
consumes:
- application/json
produces:
- application/json
security:
-
responses: ...
And also simply making security a None object:
options:
consumes:
- application/json
produces:
- application/json
security:
responses: ...
In both cases, I get the following error when attempting to deploy with aws sam deploy:
Waiting for changeset to be created.. Error: Failed to create
changeset for the stack: my-app, ex: Waiter ChangeSetCreateComplete
failed: Waiter encountered a terminal failure state Status: FAILED.
Reason: Transform AWS::Serverless-2016-10-31 failed with: Internal
transform failure.
Which seems to that my security definition is wrong. How do I disable security for one method of a resource (namely the OPTIONS method)?
UPDATE:
I got the template to deploy by using the following syntax:
options:
consumes:
- application/json
produces:
- application/json
security:
- {}
responses:
However, even after deploying, I still have this in my console:
I'm honestly at a loss right now because this is so easy to do with a regular AWS::ApiGateway::Method resource (just set ApiKeyRequired to true).
You can simply set AddDefaultAuthorizerToCorsPreflight: false that will cause OPTIONS requests to be unsecured as you wished.
See this part of documentation:
If the DefaultAuthorizer and Cors properties are set, then setting AddDefaultAuthorizerToCorsPreflight will cause the default authorizer to be added to the Options property in the OpenAPI section.
Ref: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-apiauth.html
Not great but I think you'll have to disable api_key on every OPTIONS method -- provide definition of the method with openapi and skip/omit 'security' key in it
AddDefaultAuthorizerToCorsPreflight: false does omit the default Authorizer, which can be one of CognitoAuthorizer | LambdaTokenAuthorizer | LambdaRequestAuthorizer, but unfortunately it does not omit the ApiKeyRequired. ApiKey would still be required on preflight requests. However, browsers do not attach X-API-Key Header to OPTIONS request.
Skipping ApiKey requirement manually for each preflight request seems to be the only option. Unfortunately I have no idea how to do that other than through the console manually after each deployment.
I have opened an issue on github here: https://github.com/aws/aws-sam-cli/issues/3735
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)