I've made a Lambda / API Gateway function that has a proxy param as the final param in the URL.
page:
handler: handlers/website/getRenderedPage.get
events:
- http:
method: get
path: /content/{website}/{proxy+}
cors: true
request:
parameters:
paths:
proxy: true
website: true
So, as defined, this is the behavior I'm experiencing:
/content/site.com/blog/hello-world --> website: site.com, proxy: blog/hello-world --> URL works successfully in browser.
/content/site.com --> website: site.com --> URL fails in browser (missing authentication token, aka API resource not found).
Is it possible to make that {proxy+} parameter optional?
Just have it listen to two events.
/content/{website} and
/content/{website}/{proxy+}
Related
Have really been struggling with CORs lately, and finally got a combination that works. However based on all of the documentation I have read, it should NOT work.
From the "Configuring CORS" documentation on Apollo GraphQL:
Pass the credentials option e.g. credentials: 'same-origin' if your
backend server is the same domain, as shown below, or else
credentials: 'include' if your backend is a different domain.
Since my front end is on EC2 and Backend is on Lambda, they are on different origins no?
My stack:
Frontend: Apollo Client / NextJS (hosted on EC2) ex: http://mysite.io
Gateway: AWS API Gateway ex: https://XXXXXXXXX.execute-api.us-east-1.amazonaws.com/dev/graphql
Backend: Apollo Server GraphQL (hosted on Lambda)
Note: the below code works.
Frontend:
const link = createHttpLink({
uri: process.env.API_URL,
credentials: 'same-origin',
headers: {
'x-api-key': process.env.API_KEY
}
});
Gateway Settings:
Backend:
exports.handler = server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: true,
credentials: true
}
},
});
But if I change my credential value to 'include' on the apollo client (front end)...
We run into the following preflight error:
Response to preflight request doesn't pass access control check: The
value of the 'Access-Control-Allow-Origin' header in the response must
not be the wildcard '*' when the request's credentials mode is
'include'.
I'm working on AWS Lambda using serverless framework and I need to specify two methods in functions.yml for each of the API. For example, if I have to create an endpoint for getting books http://basic-url.com/api/books/all. I have to add two methods for it in functions.yml as follows.
get_books:
handler: books/handler.get_books
tags:
Name: get-books
events:
- httpApi:
method: GET
path: /api/books/all
get_books_preflight:
handler: default/handler.get_preflight
tags:
Name: get-preflight
events:
- httpApi:
method: OPTIONS
path: /api/books/all
I have to specify preflight for all of endpoints that I want to create in functions.yml. Is there any way to manage these preflight endpoints for each endpoint automatically?
There is no need to create a function for each preflight endpoint.
When a browser receives a non-simple HTTP request, the CORS protocol requires the browser to send a preflight request to the server and wait for approval (or a request for credentials) from the server before sending the actual request. The preflight request appears to your API as an HTTP request that:
Includes an Origin header.
Uses the OPTIONS method.
Includes the following headers:
Access-Control-Request-Method
Access-Control-Request-Headers
To support CORS, therefore, a REST API resource needs to implement an OPTIONS method that can respond to the OPTIONS preflight request with at least the following response headers mandated by the Fetch standard:
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Origin
With Serverless Framework you can do this in two easy steps:
Add the cors: true flag to each HTTP endpoint in your serverless.yml:
getBooks:
handler: books/handler.getBooks
tags:
Name: get-books
events:
- http:
path: /api/books/all
method: GET
cors: true
Add the following headers to your response:
module.exports.getBooks = (event, context, callback) => {
// Do work to retrieve a Book
const book = retrieveBook(event);
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Headers': 'Authorization',
},
body: JSON.stringify({
book: book
}),
};
callback(null, response);
};
Eventually, if you use Javascript, take a look to Middy middleware engine for use with Lambda. It has a lot of nice middlewares and one is the cors middleware, which automatically adds CORS headers to your functions.
I'm trying to create a function with CORS enabled.
The function works as expected using Postman (cors headers present), but I get CORS error when trying from a browser (no cors header).
const getTicket = async event => {
var ticketNumber = Date.now();
return {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Origin': '*',
},
statusCode: 200,
body: JSON.stringify({"ticketNumber": ticketNumber})
};
};
functions:
getTicket:
handler: code/common/ticket.getTicket
runtime: nodejs12.x
events:
- http:
method: get
path: getTicket
cors: true
authorizer:
arn: ${self:custom.auth0.authorizer_arn}
I also tried few more ways of writing the serverless.yaml file, but none of them worked, the only difference between them being the created methods in my API Gateway. Sometimes I got GET+OPTIONS methods, sometimes only GET, but never worked with CORS.
I get the error:
"Access to XMLHttpRequest at 'https://...amazonaws.com/prod/getTicket' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
What you are likely seeing is that the server is returning an error before it reaches your return statements. In other words, API Gateway is returning a 502 or 403 (as these are the most common errors), and those specific returns have no CORS headers present by default in API Gateway. I would recommend using CloudWatch to inspect the specific Lambda invocations to determine if your Lambda function itself is erroring out and correct that.
You can also force your API Gateway to return the CORS headers for all responses. In the resources section of the serverless.yml file you can do the following and add any additional entries for other status codes:
resources:
Resources:
GatewayResponseDefault4XX:
Type: 'AWS::ApiGateway::GatewayResponse'
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
ResponseType: DEFAULT_4XX
RestApiId:
Ref: 'ApiGatewayRestApi'
I’m trying to custom my api gateway websocket endpoint via serverless because I need to initialize it for cloudfront which is deployed before websocket.
The initialize code is below:
ApiGatewayWebsocketApi:
Type: AWS::ApiGatewayV2::Api
Properties:
Name: ${self:provider.stage}-${self:provider.variant}-WebsocketApi
ProtocolType: WEBSOCKET
RouteSelectionExpression: "$request.body.action"
Description: "WebSocket API for ${self:provider.variant}"
And I exported it as an output:
ApiGatewayWebsocketApiId:
Value:
Ref: ApiGatewayWebsocketApi
Export:
Name: ${self:custom.configFile.appCode}-${self:provider.stage}-${self:provider.variant}-ApiGatewayWebsocketApiId
Then ApiGatewayWebsocketApiId will represent an endpoint string like b6hnpuyzq6
And I can get it in websocket serverless.yml:
WebSocketApiId:
Fn::ImportValue: ${self:custom.configFile.appCode}-${self:provider.stage}-${self:provider.variant}-ApiGatewayWebsocketApiId
But here is the problem:
how can I import it to my function such as connectionHandler so that this websocket can use the endpoint imported above:
connectionHandler:
name: ${self:provider.stage}-${self:provider.variant}-${self:custom.configFile.appCode}-ws-connection
handler: WebsocketTestHandler
events:
- websocket:
route: $connect
- websocket:
route: $disconnect
Perhaps you can try to pass WebSocketApiId parameter value trough WEB_SOCKET_API_ID environment variable available in the handler, like this:
connectionHandler:
name: ${self:provider.stage}-${self:provider.variant}-${self:custom.configFile.appCode}-ws-connection
handler: WebsocketTestHandler
environment:
WEB_SOCKET_API_ID:
Ref: WebSocketApiId
events:
- websocket:
route: $connect
- websocket:
route: $disconnect
How to pass the pathParameter user_id to the first function in a Step Function?
PS: I'm using API Gateway to invoke the step function.
stepFunctions:
stateMachines:
hellostepfunc:
name: HelloStep
events:
- http:
path: users/list/{user_id}
method: GET
cors: true
authorizer: aws_iam
You can try something like below, hope it helps.
serverless.yml
events:
— http:
path: users/list/{user_id}
method: get
cors: true
request:
parameters:
paths:
user_id: true