I was testing out the new API Gateway to secure a cloud function for my React application. So far the process has been much nicer than the previous alternatives, but I am currently getting CORS errors when trying to reach out to my API Gateway from my React app. I am setting the CORS headers correctly in my Cloud Function, but I have no known way of doing the same on the API Gateway endpoint. I am using Postman to test a request to the gateway endpoint and everything is working great, so it is just when I request from my React app.
Error: "Access to fetch at 'https://my-gateway-a12bcd345e67f89g0h.uc.gateway.dev/hello?key=example' from origin 'https://example.netlify.app' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
Would love some insight into this issue. Thanks!
This is not yet supported, however, there is a temporary workaround to get this working. You should add options
to the paths in your openapi.yaml
. Additionally, both get
and options
operations should point to the same cloud function, since the options
request then acts as a warmup request for the cloud function. This is the most efficient setup, in terms of latency. Here is a simplified example:
paths:
/helloworld:
get:
operationId: getHelloWorld
x-google-backend:
address: $CLOUD_FUNCTION_ADDRESS
responses:
'200':
description: A successful response
options:
operationId: corsHelloWorld
x-google-backend:
address: $CLOUD_FUNCTION_ADDRESS
responses:
'200':
description: A successful response
Then, in your cloud function backend, you must also handle the preflight request (source). The Google documentation also provides an example with authentication, which has some additional headers. Here is an example without authentication:
def cors_enabled_function(request):
# For more information about CORS and CORS preflight requests, see
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# for more information.
# Set CORS headers for the preflight request
if request.method == 'OPTIONS':
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '3600'
}
return ('', 204, headers)
# Set CORS headers for the main request
headers = {
'Access-Control-Allow-Origin': '*'
}
return ('Hello World!', 200, headers)
Note: the downside of API gateway not managing preflight requests in a proper manner results in a penalty of running the cloud function twice. But your second request should always be very fast since the first request acts as a warmup request.
Turns out that API Gateway does not currently have CORS support.
Reference.
Solution
Here is the solution. It is just as user14982714 stated. Add a host and x-google-endpoints to your oepnapi.yaml
file at the top level:
host: my-cool-api.endpoints.my-project-id.cloud.goog
x-google-endpoints:
- name: my-cool-api.endpoints.my-project-id.cloud.goog
allowCors: True
However, be sure to replace my-cool-api.endpoints.my-project-id.cloud.goog
with your API Managed Service URL. This can be found in your google cloud console under the API Gateway API here:
I covered the start to my endpoint name for privacy, however, yours should also end with .cloud.goog
. If you haven't deployed a configuration yet, deploy it without the x-google-endpoints and host, then update it to include both. (To update your configuration go to API Gateway -> Your API -> Gateways Tab -> Your Gateway -> Edit- > Change API Config -> Create New)
Explanation
Now to explain why this works with Google Cloud API Gateway. The API Gateway uses endpoints under the hood. Most people don't know this is the case, however, after giving up on the API Gateway and moving back to Endpoints I noticed that my API Gateways were listed under the endpoint services. They do not show in the UI, but with the gcloud CLI, run this command gcloud endpoints services list
and you should see your API Gateways. Crazy! But Google does this a lot.
So knowing this I tried adding allowCors: true
to the x-google-endpoints
and viola. It worked. I hope this helps someone out there.
swagger: "2.0"
host: "my-cool-api.endpoints.my-project-id.cloud.goog"
x-google-endpoints:
- name: "my-cool-api.endpoints.my-project-id.cloud.goog"
allowCors: True
Note: host and name should have the same API endpoint name
Configuring these lines in your config file enables CORS for API GATEWAY
[Reference][1]
[1]: https://cloud.google.com/endpoints/docs/openapi/support-cors#:~:text=CORS%20(Cross%2Dorigin%20resource%20sharing,would%20prevent%20cross%2Dorigin%20requests.
I had the same issue and solve it with a load balancer (originally used to add a custom domain to my API gateway). I use my load balancer to add the missing header into the response.
You just need to add the "Access-Control-Origin" header:
Allow all
Access-Control-Origin:'*'
Allow a specific origin Access-Control-Allow-Origin: http://example.com:8080
You can find the instructions here GCP - Creating custom headers.
If you do not have a load balancer implemented, you can follow this tutorial to implement a new one Google API Gateway, Load Balancer and Content Delivery Network.
You can find more information regarding CORS at https://www.w3.org/wiki/CORS_Enabled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With