GCP API Gateway Open API definition, can it be partial? - google-cloud-platform

API Gateway in GCP requires an Open API definition. It looks like this definition must be very precise (includes all HTTP methods and all endpoints). Ex:
paths:
/v1/hello:
get:
summary: Hi Service
operationId: hello-v1
x-google-backend:
address: <CLOUD_RUN_URL>
responses:
'200':
description: OK
Is there something in the spec to define only partial definitions? End goal would be to use API Gateway as a kind of reverse proxy.
Example:
anything behind /path1 goes to Cloud Run URL 1,
anything behind /path2 goes to Cloud Run URL 2.

You are able to create this figure
and by adding the relavant path-rules you can accomplish what you described
gcloud compute url-maps add-path-matcher api-gateway-url-map \
--path-matcher-name=my-pm2 \
--default-service=my-host-default-backend \
--path-rules="/video=video-service,/video/*=video-service" \
--new-hosts my-hosts.com
See the full documentation page for: Getting started with HTTP(S) Load Balancing for API Gateway

You can set up a wildcard and path_translation
/v1/hello/{another_path=**}:
get:
summary: Hi Service
operationId: hello-v1
x-google-backend:
address: <CLOUD_RUN_URL>
path_translation: APPEND_PATH_TO_ADDRESS
responses:
'200':
description: OK
That means that the path <API_GATEWAY_URL>/v1/hello/world/123 will be forwarded to <CLOUD_RUN_URL>/v1/hello/world/123

Related

API Gateway V2 Http API mapping returning "Not Found" when a "Path" is provided in the API mappings

I've searched a lot of the "Not Found" errors on StackOverflow, along with other APIGW HTTP posts, and they don't match this exact scenario.
Tldr: Custom domain with APIGW V2 HTTP works when the "Path" is blank in the API mappings, but returns 404 "Not Found" when I add the exact path.
Details
I'm using a custom domain (dev.myapp.com) configured in API Gateway. The DNS is setup correctly as you will see shortly.
Here is the API mapping I have setup:
The issue is:
When I use the optional "Path", and invoke dev.myapp.com/oauth/callback/app the API Response returns 404 "Not Found"
I have logs enabled for the HttpApi and the logs don't show any events, so I'm guessing it is not matching to the mapping
When I remove the optional "Path", then invoking dev.myapp.com/oauth/callback/app returns a successful 200
The logs show for the API that is mapped in this case
Been trying to solve this for a day and a half now. Tried many things like re-deploying, etcc.. I need to have multiple API mappings for this custom domain so using a single mapping with the Path field blank is not an option.
Other info:
Custom domain config's "Endpoint type" is "Regional"
The API is hooked up to invoke a lambda, which works properly when the "Path" is removed in the API mappings
I'm using Serverless Framework to deploy the V2 API. Here is part of the serverless yml:
app: myApp
service: ${self:app}-callback
provider:
name: aws
runtime: nodejs16.x
region: us-east-1
logs:
httpApi: true # enable httpApi logs
functions:
oauth-callback:
handler: src/infra/oauth-app-callback-service/index.handler
name: ${self:service}-oauth-callback-${sls:stage}
events:
- httpApi:
path: /oauth/callback/app
method: GET
I've tried re-deploying, smaller "path" such as only oauth, turning off "default endpoint", but none have worked. I've looked at this solution but its a different issue which was with load balancer path rules which is not applicable here
What I expect is when using APIGW V2 HTTP with a custom domain and an API mappings with a "Path", the mapped API should be found and not return "Not Found"
After much searching, I went to AWS's community and found this post.
Go to your API Gateway and select Route
Click Create
Leave the Any method as is and type in the path $default without a leading slash.
Click on Attach integration and select your web service endpoint
This worked and I no longer get the 404. Only issue is I have to do this manually and can't do this via Serverless Framework. I'll post a comment here if I figure it out.
Edit:
To set this automatically up with serverless framework, you need to use the $default path, which can only be done as such:
functions:
oauth-callback:
handler: src/infra/oauth-app-callback-service/index.handler
name: ${self:service}-oauth-callback-${sls:stage}
events:
- httpApi: '*'
Now you're custom domain API mapping will work without having to deploy and then set the $default route for each API.

Path parameters ignored by AWS API Gateway using proxy+

I have a REST API on the AWS API Gateway. It has one resource, /{proxy+}, that is configured with the ANY method. The integration request is setup to be a VPC_PROXY, meaning its using a VPC Link. The VPC link is to a network load balancer that is fronting an app I have running on an ECS cluster using Fargate.
When using the console's option to test the API, I can confirm that requests are reaching my app but the resource being requested is always / according to my logging. If I attempt to set the {proxy} value in the method test screen on the console, it seems like my app only ever gets requests for /. If I set {proxy} to something like widget/5, the response I receive is as if I was request /.
I'm wondering if there is some way to troubleshoot this, scouring the AWS documentation I can't figure out where I'm going wrong with my setup.
In your integration, the endpoint URL should be http://loadbalancerurl/{proxy}. I couldn't find any documentation specifically for VPC Link integration, but there is a tutorial for HTTP proxy integration which has similar steps.
If you are using openapi spec, the integration section would look something like this:
x-amazon-apigateway-integration:
uri: "http://loadbalancerurl/{proxy}"
responses:
default:
statusCode: "200"
requestParameters:
integration.request.path.proxy: "method.request.path.proxy"
passthroughBehavior: "when_no_match"
connectionType: "VPC_LINK"
connectionId: "your-vpclink-id"
httpMethod: "ANY"
type: "http_proxy"
When using the console, integration.request.path.proxy: "method.request.path.proxy" mapping was added automatically when I added {proxy} to my endpoint URL.
What works for me is by adding the following properties:
Resources:
APIGWProxyMethod:
Type: AWS::ApiGateway::Method
Properties:
RequestParameters:
method.request.path.proxy: true # enable proxy
Integration:
RequestParameters:
integration.request.path.proxy: method.request.path.proxy # map method proxy param to integration proxy param
... # the rest of integration property
... # other properties
Articles that helped:
https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-proxy-path-character-error/
https://aws.amazon.com/premiumsupport/knowledge-center/api-gateway-proxy-path-parameter-error/

GCP: configure cloud ESPv2 endpoint with x-google-backend Parameters

I am using gcp cloud endpoint with a cloud run backend Service. My Problem is that the backend is configured with a default timeout of 15 seconds. Thats why I would like to set openAPI "x-google-backend" deadline parameter to increase timeout for the endpoint: (https://cloud.google.com/endpoints/docs/openapi/openapi-extensions)
Currently I am using the following grpc service configuration for my endpoint.
https://cloud.google.com/endpoints/docs/grpc/grpc-service-config
openAPI extension is not supported for this kind of configuration. Now I am looking for a way to combine
the grpc configuration with openAPI. I have read that it is possible to publish several configuration files for one endpoint.
OK, this kind of configuration works well.
type: google.api.Service
config_version: 3
name: ${cloud_run_hostname_endpoint}
title: ${endpoint_title}
apis:
- name: my_endpoint_name
usage:
rules:
# No APIs can be called without an API Key
- selector: "*"
allow_unregistered_calls: false
backend:
rules:
- selector: "*"
address: grpcs://${cloud_run_hostname_backend}
deadline: 300.0
deadline parameter is accepted.

AWS API Gateway integration with AWS Event Bridge(Cloudwatch Events) in Cloudformation Script

Original Requirement:
Create a route/path on AWS Api Gateway which connects API Gateway directly to AWS Event Bridge (Cloudwatch Events) and puts/pushes event on an event bus of it.
Was able to create it and executes just fine when done from AWS Console.
Actual Problem:
When writing the AWS Cloudformation script for this API Gateway, it looks like this:
EventsPostMethod:
Type: AWS::ApiGateway::Method
Properties:
ResourceId:
Ref: EventsResource
RestApiId:
Ref: RestAPI
HttpMethod: POST
AuthorizationType: NONE
Integration:
Type: AWS
IntegrationHttpMethod: POST
Uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents
RequestParameters:
integration.request.header.X-Amz-Target: "'AWSEvents.PutEvents'"
RequestTemplate:
some-script-here...
Notice the Uri value:
"arn:aws:apigateway:${AWS::Region}:cloudwatchEvents:action/PutEvents"
arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}
According to AWS Docs the value of uri should be following:
For AWS or AWS_PROXY integrations, the URI is of the form arn:aws:apigateway:{region}:{subdomain.service|service}:path|action/{service_api}. Here, {Region} is the API Gateway region (e.g., us-east-1); {service} is the name of the integrated AWS service (e.g., s3); and {subdomain} is a designated subdomain supported by certain AWS service for fast host-name lookup. action can be used for an AWS service action-based API, using an Action={name}&{p1}={v1}&p2={v2}... query string. The ensuing {service_api} refers to a supported action {name} plus any required input parameters. Alternatively, path can be used for an AWS service path-based API. The ensuing service_api refers to the path to an AWS service resource, including the region of the integrated AWS service, if applicable. For example, for integration with the S3 API of GetObject, the uri can be either arn:aws:apigateway:us-west-2:s3:action/GetObject&Bucket={bucket}&Key={key} or arn:aws:apigateway:us-west-2:s3:path/{bucket}/{key}
You must have noticed that I replaced the service with cloudwatchEvents in the above mentioned uri.
Now, error Given by AWS Cloudformation Console during Publish of API Gateway:
AWS Service of type cloudwatchEvents not supported (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 07bae22c-d198-4595-8de9-6ea23763eff5; Proxy: null)
Now I have tried replacing service with
cloudwatch
eventBridge
cloudwatchEvent
event-bus
This is the real problem. What should I place in service in uri so that it accepts ?
Based on the comments,
The URI should be something like below for events:
arn:aws:apigateway:${AWS::Region}:events:action/PutEvents

Endpoint for Cloud Function returns 403 Forbidden

I am following Google's tutorial for setting up an Endpoint for my cloud function.
When I try to access the endpoint from my browser using URL service_name.a.run.app/function1 I get
Error: Forbidden
Your client does not have permission to get URL /function1GET from this server
As part of the mentioned tutorial and answer from a Google product manager , I'm securing my function by granting ESP permission to invoke my function.
gcloud beta functions add-iam-policy-binding function1 --member "serviceAccount:id-compute#developer.gserviceaccount.com" --role "roles/cloudfunctions.invoker" --project "project_id"
My openapi-functions.yaml
swagger: '2.0'
info:
title: Cloud Endpoints + GCF
description: Sample API on Cloud Endpoints with a Google Cloud Functions backend
version: 1.0.0
host: HOST
x-google-endpoints:
- name: "HOST"
allowCors: "true
schemes:
- https
produces:
- application/json
paths:
/function1:
get:
operationId: function1
x-google-backend:
address: https://REGION-FUNCTIONS_PROJECT_ID.cloudfunctions.net/function1GET
responses:
'200':
description: A successful response
schema:
type: string
Note that I added
- name: "HOST"
allowCors: "true'
to my .yaml file because I need to access the endpoint from a static site hosted on Firebase.
I have followed the tutorial you have mentioned, and indeed I came across the exact same error.
Nothing regarding permissions and roles seemed wrong.
After digging a bit what solved the issue was removing the “GET” at the end of the address.
So the openapi-functions.yaml would be like this:
swagger: '2.0'
info:
title: Cloud Endpoints + GCF
description: Sample API on Cloud Endpoints with a Google Cloud Functions backend
version: 1.0.0
host: [HOST]
schemes:
- https
produces:
- application/json
paths:
/function-1:
get:
summary: Greet a user
operationId: function-1
x-google-backend:
address: https://[REGION]-[PROJECT_ID].cloudfunctions.net/function-1
responses:
'200':
description: A successful response
schema:
type: string
Then make sure you are following all the steps mentioned in the tutorial correctly (except the above part).
In case you get a Permissions Denied error when running any of the steps, try running it again as sudo.
I have also tried adding the same as you:
host: [HOST]
x-google-endpoints:
- name: [HOST]
allowCors: "true"
And all is working well.
Pay extra attention to the CONFIG_ID that changes with each new deployment
Example:
2019-12-03r0
then it goes like:
2019-12-03r1
In case the deployment step fails (it shows some successful messages but it might fail in the end), then make sure you delete the existing endpoint service to avoid issues:
gcloud endpoints services delete [SERVICE_ID]
Also you can use the following to give cloudfunctions.invoker role to all users (Just for testing)
gcloud functions add-iam-policy-binding function-1 \
--member="allUsers" \
--role="roles/cloudfunctions.invoker"