Custom api gateway websocket endpoint using serverless - websocket

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

Related

AWS SAM app API multiple method declarations

I created AWS sam application. It has a REST API customers. Presently I'm able to add only one http method type either GET or POST.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: ""
Globals:
Function:
Timeout: 59
Resources:
HealthFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: src/
Handler: index.handler
Runtime: nodejs14.x
Architectures:
- x86_64
Events:
Health:
Type: Api
Properties:
Path: /health
Method: get
Customers:
Type: Api
Properties:
Path: /customers
Method: get
Outputs:
HealthApi:
Description: "API Gateway endpoint URL for Prod for Health function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/health"
CustomersApi:
Description: "API Gateway endpoint URL for Prod for Health function"
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/customers"
How can I declare customers API http methods both GET and POST?
You can define multiple events for the same path.
CustomersGetEvent:
Type: Api
Properties:
Path: /customers
Method: GET
CustomersPostEvent:
Type: Api
Properties:
Path: /customers
Method: POST
As an alternative you can also use Method: ANY.

Is there any way to automatically manage preflight endpoints for each of the endpoint in serverless (AWS Lambda)

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.

serverless framework AWS REST API Gateway - 403 CORS error

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'

How to access API Gateway's pathParameters in step function using Serverless framework?

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

Lambda + API Gateway: optional proxy param

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+}

Resources