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.
Related
I don't understand the following behavior of my API Gateway and Cognito User Pool Authorizer. Using the AWS SAM template, I have deployed the following Cognito User Pool:
CognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref CognitoUserPool
ClientName: !Sub CognitoUserPoolClient-${StageName}
GenerateSecret: false
SupportedIdentityProviders:
- COGNITO
ExplicitAuthFlows:
- ALLOW_USER_PASSWORD_AUTH
- ALLOW_CUSTOM_AUTH
- ALLOW_REFRESH_TOKEN_AUTH
- ALLOW_USER_SRP_AUTH
OptalXCognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
AutoVerifiedAttributes:
- email
EmailVerificationSubject: Verify your email.
EmailVerificationMessage: Please click the link below to verify your email address. {####}
EmailConfiguration:
EmailSendingAccount: DEVELOPER
From: Widgets Co <admin#widgets.com>
ReplyToEmailAddress: admin#widgets.com
SourceArn: !FindInMap [ StageMap, !Ref StageName, EmailSESArn ]
UserPoolName: !Sub CognitoUserPool-${StageName}
VerificationMessageTemplate:
DefaultEmailOption: CONFIRM_WITH_LINK
AdminCreateUserConfig:
AllowAdminCreateUserOnly: true
UnusedAccountValidityDays: 90
InviteMessageTemplate:
EmailMessage: ...
EmailSubject: Welcome to Widgets Co!
SMSMessage: Your username is {username} and temporary password is {####}.
Policies:
PasswordPolicy:
MinimumLength: 8
UsernameAttributes:
- email
Schema:
- AttributeDataType: String
Name: user_id
Mutable: false
DeveloperOnlyAttribute: false
- Name: email
Mutable: false
Required: true
Then, I've defined an API Gateway that uses the Cognito User Pool as its Authorizer:
WidgetsAPI:
Type: 'AWS::Serverless::Api'
Name: WidgetsAPI
Properties:
GatewayResponses:
EXPIRED_TOKEN:
ResponseParameters:
Headers:
Fail-Reason: "'Expired token'"
Access-Control-Allow-Origin: "'*'"
DEFAULT_4xx:
ResponseParameters:
Headers:
Access-Control-Expose-Headers: "'WWW-Authenticate'"
Access-Control-Allow-Origin: "'*'"
DEFAULT_5XX:
ResponseParameters:
Headers:
Fail-Reason: "'Internal server error. Check logs.'"
Access-Control-Allow-Origin: "'*'"
Auth:
DefaultAuthorizer: CognitoAuthorizer
Authorizers:
CognitoAuthorizer:
UserPoolArn: !FindInMap [ StageMap, !Ref StageName, UserPoolArn ]
AddDefaultAuthorizerToCorsPreflight: false
Here my UserPoolArn is inside a Mappings that differs based on the environment we are in (stage or prod). I've defined a bunch of endpoints, but for the sake of demonstration, there's on called /users.
Now when I pass in a GET /prod/users request, with a header of Authorization: THE_ID_TOKEN_FROM_MY_COGNITO_SIGN_IN, I receive a 401 Unauthorized. I can 100% confirm that I am using the right ID token. For instance, when I pass in the same ID token to test via the management console's authorizer screen, I get a 200 response:
Moreover, I've deployed in our company's stack multiple API endpoints, all with the same pattern - we've been using id_token for the past year quite successfully. The only difference is we are trying to move our managed user pools into CloudFormation templates, so the most recent User Pool (including this problematic one) were created via aws sam build.
Why is this happening? I know I may not have provided enough details, but happy to add any other pieces of code or configs that are relevant. It's hard for me to reproduce this error since in all my other environments (stage, my other microservices API endpoints), the API Gateway and Cognito User Pool work perfectly after being deployed via AWS SAM.
In fact, I've deployed the exact same version of this infrastructure in our staging environment, and it works perfectly (the only difference between our stage and prod environments is the Stage parameter that we pass into our template YAML stack).
I've found that if I go into the management console and manually deploy the API again, everything works great (I get a 200 response with the expected response output):
Note - there's several posts (here, here, and here) about this topic, but none of them describe my exact problem, which is why my API Gateway returns 401 Unauthorized errors upon first applying my Cloudformation stack, and only works properly after I manually deploy from the console the entire API Gateway stage.
Add a AWS::ApiGateway::Deployment resource to your template.
ApiGatewayDeployment:
DependsOn:
- Function1Name
- Thing2Name
Type: AWS::ApiGateway::Deployment
Properties:
RestApiId: !Ref WidgetsAPI
StageName: !Sub ApiGateway-${ApiGatewayStageName}
now sam deploy will have your api deploy to "ApiGateway-loremipsum"
I'm trying to setup Google API Gateway to use an API key that callers send in the header.
My api config yaml looks like this:
...
securityDefinitions:
api_key_header:
type: apiKey
name: key
in: header
api_key_query:
type: apiKey
name: key
in: query
paths:
/foo-header:
get:
summary: Test foo endpoint
operationId: testGet-header
x-google-backend:
address: "<backend address>"
protocol: h2
path_translation: APPEND_PATH_TO_ADDRESS
security:
- api_key_header: []
responses:
204:
description: A successful response
/foo-query:
get:
summary: Test foo endpoint
operationId: testGet-header
x-google-backend:
address: "<backend address>"
protocol: h2
path_translation: APPEND_PATH_TO_ADDRESS
security:
- api_key_query: []
responses:
204:
description: A successful response
I expect both calls, /foo-header and /foo-query to fail with 401 status if a valid API key is not provided via header or query parameter.
But in a fact only /foo-query behaves as expected.
Requests to /foo-header pass to the backend even when the API key is not provided in request header.
Do I have issue with the config, or is it the Google API Gateway that doesn't work properly when API key is provided in request header?
When in is header, the name should be x-api-key.
https://cloud.google.com/endpoints/docs/openapi/openapi-limitations#api_key_definition_limitations
It seems that the Google API Gateway should work fine when the API key is provided in request header since the Google API Gateway documentation states:
A developer generates an API key in a project in the Cloud Console and embeds that key in every call to your API as a query parameter or in a request header.
However, I was able to reproduce the behavior you reported, thus I don't think that there is something wrong in your configuration.
For that I'd been following the GCP quickstart for the Google API Gateway, modifying it slightly so that my OpenAPI spec would also have 2 paths: one is looking for a key in query parameters, while another in the request header.
paths:
/foo-header:
get:
summary: Test security
operationId: headerkey
x-google-backend:
address: [MY_CLOUD_FUNCTION_1]
security:
- api_key_header: []
responses:
'200':
description: A successful response
schema:
type: string
/foo-query:
get:
summary: Test security
operationId: querykey
x-google-backend:
address: [MY_CLOUD_FUNCTION_2]
security:
- api_key_query: []
responses:
'200':
description: A successful response
schema:
type: string
securityDefinitions:
# This section configures basic authentication with an API key.
api_key_header:
type: "apiKey"
name: "key"
in: "header"
api_key_query:
type: "apiKey"
name: "key"
in: "query"
Just like you, I could see the requests to the /foo-header pass to the backend even when there was no API key provided.
I would suggest you to report this issue on the Public Issue Tracker, so that it would be reviewed by an appropriate GCP engineering team.
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
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: "'*'"
I've been trying to create a method in API Gateway that drops the body of the incoming request into a file/object in an S3 bucket. But I want the method to create a new file each time (so a file with a new name) instead of overwriting the previous one. But I've been struggling to find a way to do it. Anyone has any suggestions/ideas? Something like a timestamp, or a sequence number (or both) to use as a variable in the Path override so that it would become the name of the s3 file. I looked at suggestions to use the X-Amzn-Trace-Id but it doesn't seem to be available in Path override. Anything else I could try? Maybe something in Swagger? I want to achieve it using API Gateway (avoid using a lambda as an extra step) to keep our architecture from getting too complex. Thanks in advance!
You can set the X-Amzn-Trace-Id as the method parameter, then map the parameter to the integration parameter on the path to S3 as the object name .
Example:
---
swagger: "2.0"
info:
version: "2017-12-04T23:03:26Z"
title: "API"
host: "xxxx.execute-api.us-east-1.amazonaws.com"
basePath: "/dev"
schemes:
- "https"
paths:
/:
post:
produces:
- "application/json"
parameters:
- name: "X-Amzn-Trace-Id"
in: "header"
required: false
type: "string"
responses:
200:
description: "200 response"
schema:
$ref: "#/definitions/Empty"
x-amazon-apigateway-integration:
credentials: "arn:aws:iam::178779171625:role/api-gate-way"
responses:
default:
statusCode: "200"
requestParameters:
integration.request.path.traceid: "method.request.header.X-Amzn-Trace-Id"
uri: "arn:aws:apigateway:us-east-1:bucketName.s3:path/{traceid}"
passthroughBehavior: "when_no_match"
httpMethod: "PUT"
type: "aws"
definitions:
Empty:
type: "object"
title: "Empty Schema"