Error code 500 when calling API from client - amazon-web-services

I have a Lambda function and when I call it from my React app I get the following 2 errors:
POST https://x7429ccke5.execute-api.eu-west-1.amazonaws.com/prod/sites 500
and
Uncaught (in promise) Error: Request failed with status code 500
at createError (createError.js:17)
at settle (settle.js:19)
at XMLHttpRequest.handleLoad (xhr.js:78)
I do not have a log in system on my website yet so I want to call the api without needed permission so on my serverless.yml, I have it as
functions:
# Defines an HTTP API endpoint that calls the main function in create.js
# - path: url path is /notes
# - method: POST request
# - cors: enabled CORS (Cross-Origin Resource Sharing) for browser cross
# domain api call
# - authorizer: authenticate using the AWS IAM role
createSite:
handler: CreateSite.main
events:
- http:
path: sites
method: post
cors: true
arn: "arn:aws:execute-api:eu-west-1:106845550704:x7429ccke5/*/POST/sites"

I am suspecting the problem is with API Gateway's integration with lambda. It's your API Gateway that is throwing the 500 error. Please check if your API Gateway is staged or not. If it's staged then check for this:
https://docs.aws.amazon.com/apigateway/latest/developerguide/amazon-api-gateway-using-stage-variables.html#call-api-http-backend-via-stage-variable
Let me know if it still doesn't work.

Related

Serverless AWS Access-Control-Allow-Headers in preflight response

For some reasom this error appears from nowhere:
has been blocked by CORS policy: Request header field x-company-id is not allowed by Access-Control-Allow-Headers in preflight response.
Here is my serverless.yml lambda function:
healthPlan:
handler: src/handlers/health-plan.healthPlanHandler
events:
- http:
path: /health-plan
method: get
cors:
origin: ${self:custom.allowed-origin}
allowCredentials: ${self:custom.allow-credentials}
headers:
- Content-Type
- X-Amz-Date
- Authorization
- X-Api-Key
- X-Amz-Security-Token
- X-Amz-User-Agent
- X-Company-Id
- x-company-id
authorizer:
authorizerId: ${cf:auth-service-${self:provider.stage}.ApiAuthorizer}
type: TOKEN
I'm new to serverless. Could someone give me advice or the answer for current situation? Where should I look?
Thanks a lot for help!
Firstly, are you sure you need x-company-id? I see you have also X-Company-Id, which I'm guessing might be the actual header AWS expects?
Likely x-company-id is being treated as a custom header. I had this same CORS issue with Serverless and AWS when trying to pass actual custom headers to my API.
My issue was resolved by adding a resources section to serverless.yml to include CORS headers in API Gateway-level error responses and including CORS headers in the normal responses of my lambda handler.
The instructions for performing these 2 steps I found here:
https://dev.to/leventov/enable-cors-with-custom-headers-for-an-aws-lambda-function-behind-api-gateway-in-serverless-framework-3702
Note that, instead of including each header explicitly in the access-control-allow-headers field, you can also just whitelist all headers with * if this is not a security concern.

GCP: API-Gateway Cors Issue and adding custom authentication

I have configured API-Gateway to call Cloud Function, also we have configured Load Balancer for this API-Gateway host. But we are facing CORS Issue when we invoke this Load balancer end point from our web application.
Question 1: Please guide me on how to add CORS support at API config open-api YAML file.
Question 2: How To add Custom authentication endpoint to this open-api config YAML file?
High level flow: webapp --> load balancer url --> API-Gateway --> CloudFunction
I have added CORS backend support at cloud function as per the GCP link: https://cloud.google.com/functions/docs/writing/http#authentication_and_cors
Cloud Function code as follows:
public class Demand implements HttpFunction {
private static final Logger logger = Logger.getLogger(Demand.class.getName());
// Use GSON (https://github.com/google/gson) to parse JSON content.
private static final Gson gson = new Gson();
#Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
String contentType = request.getContentType().orElse("");
logger.info(() -> "contentType: " + contentType);
// Set CORS headers
// Allows GETs from any origin with the Content-Type
// header and caches preflight response for 3600s
response.appendHeader("Access-Control-Allow-Origin", "*");
System.out.println("Added preflight options request support::::::::::");
if ("OPTIONS".equals(request.getMethod())) {
System.out.println("OPTIONS::::::::::::::::");
response.appendHeader("Access-Control-Allow-Methods", "*");
response.appendHeader("Access-Control-Allow-Headers", "Content-Type");
response.appendHeader("Access-Control-Max-Age", "3600");
response.setStatusCode(HttpURLConnection.HTTP_NO_CONTENT);
return;
}
// Handle the main request.
BufferedWriter writer = response.getWriter();
writer.write("CORS headers set successfully!");
}
Open-API spec below:
---
info:
description: Sample API on API Gateway with a Google Cloud Functions backend
title: trigger-post
version: 1.0.0
paths:
/triggerondemand:
post:
consumes:
- application/json
operationId: triggerondemand
parameters:
- description: triggerondemand.
in: body
name: ondemand
schema:
properties:
fileStatus:
type: string
type: object
responses:
'201':
description: Created
summary: triggerondemand
x-google-backend:
address: >-
https://us-east1-neodev-305805.cloudfunctions.net/demand
produces:
- application/json
schemes:
- https
swagger: '2.0'
Browser Error as follows:
Access to XMLHttpRequest at 'https://apitest.dev.app.com/triggerondemand' from origin 'https://dataplatform.dev.app.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Thanks in advance
The answer to both your questions is that this is not possible at the moment.
The GCP API Gateway does not support the handling of CORS at the moment, although it is in the roadmap to be implemented, but you can use a workaround to do that as you can see in this community answer.
On regards to custom authentication, as I decribed in my answer here:
Unfortunately the GCP API Gateway does not provide such option for custom authentication, in order to authenticate using the API Gateway you have to use one of the alternate authentication methods provided in the documentation.

Use OpenAPI Components with AWS API Gateway

I am relatively new to AWS API Gateway. I am trying to make use of OpenAPI Components in the OpenAPI definition for the API Gateway.
I am trying to build reusable responses for the integration response as illustrated below.
This is a reusable component for 400 response (along with the mapping template for it):
components:
responses:
BAD_REQUEST:
statusCode: "400"
responseTemplates:
application/json: "#set($inputRoot = $input.path('$'))\n{ \n \"message\"\
: \"Invalid Request Body\"\n}"
And I am trying to use this under responses in the API Gateway Integration like below:
x-amazon-apigateway-integration:
<API_GATEWAY_CONFIG_GOES_HERE>
responses:
.*"BadRequest".*:
$ref: '#/components/responses/BAD_REQUEST'
When I deploy the whole CloudFormation stack I got that error and the stack could not be deployed:
Unable to put integration response on 'POST' for resource at path '/test_resource': Integration response status code must be non-empty
Any ideas?
I have spent a few days searching for this and the only possible way is YAML anchors:
You can check the code from:
How to re-use my x-amazon-apigateway-integration definition throughout Swagger YAML document?
https://github.com/aws/serverless-application-model/issues/228#issuecomment-564427077
Additionally, this official way from AWS doesn't seem to work as of now!

How to add Method Response in serverless.yml

I'm trying to add CORS header to Method Response header with serverless. Here's my config:
- http:
path: /myapi
method: GET
cors: true
My expectation is that CORS is enabled in GET method, but only OPTION method comes up. From my research, I stumbled upon this setting:
- http:
path: /myapi
method: GET
cors: true
"responseModels": {"application/json": "Empty"}
"statusCode": "200"
"responseParameters": {"method.response.header.Access-Control-Allow-Origin": true}
However nothing showed up and no error when I deployed serverless. My understanding is that a 200 response status code has to exist before CORS can be added here. When I create a new resource using UI console, a 200 status code is added automatically but serverless doesn't create it.
Any suggestion to achieve this without me creating a 200 status code manually?
This should work. I do this every day. I use Python, I set the CORS to true in serverless.yml and also must explicitly, manually, set the Access-Control-Allow-Origin to * in every response. Maybe that is not ideal, but it works for us.

API Gateway configure http integration with input passthrough serverless 1.x

Is there a way to map all parameters,headers and body to the other http endpoint? does it require a special template?
This is what I've got so far:
functions:
myfunction:
handler: lambda.myfunction # dummy hanlder
events:
- http:
path: resource/{resourceId}/other
method: get
integration: HTTP
request:
uri: http://url/resource/{resourceId}/other
parameters:
'method.request.path.resourceId': true
'method.request.header.my-header': true
response:
statusCodes:
200:
pattern: ''
Whenever i create directly in the console the the passthrough option is enabled by default and it maps the resourceId correctly.
I tried to look into the documentation but seems that there's almost no documentation on the http integration, unless i'm missing something.
Is there a way to map all parameters,headers and body to the other http endpoint? does it require a special template?
Yes, use HTTP_PROXY integration type. In the console this is a checkbox in the Integration Request page.
I was able to find a workaround to have this working, seems more a workaround than the correct solution.
I had to set the Integration.RequestParameters in the resources of the serverless.yml to achieve this.
resources:
Resources:
ApiGatewayMethodV1ResourceResourceidVarOtherGet:
Properties:
RequestParameters:
method.request.path.resourceId: true
method.request.header.my-header: true
Integration:
RequestParameters:
integration.request.path.resourceId: method.request.path.resourceId
integration.request.header.my-header: method.request.header.my-header