AWS API Gateway path based routing to private integrations - amazon-web-services

I am using AWS HTTP API Gateway to route requests to my integrations in the VPC.
I've added a custom domain and I want to route my requests to my integrations based on the paths in the following manner
Basically all the requests coming to the API gateway should be routed to different integrations based on the base paths but the integration should receive only the path after the base path. So all the requests coming to my.custom.domain/foo/<path1>/<path2>/<path3> should be routed to the integration Foo but the gateway should strip the base path i.e. /foo and forward the rest to the integration.
The functionality is same as below in nginx where nginx strips the foo from the request path and forwards the rest to the service
location /foo/ {
proxy_pass http://foo.service
}
I've tried adding custom domain and API mapping in the AWS API gateway but that doesn't work. My service still receives the whole path from the request and hence fails.
I am unable to find any documentation or mentions on the internet about this.

You can use routes and parameter mappings to achieve this.
Create 2 routes with 2 path mappings:
path: "/foo/{proxy+}" with parameter mapping: "/$request.path.proxy"
path: "/bar/{proxy+}" with parameter mapping: "/$request.path.proxy"
"proxy+" is a greedy path variable, so it will contain the path after /foo/ or /bar/.
You can use this variable with a parameter mapping to overwrite the path the backend will receive.

This is how it looks like in AWS CDK
const privateIntegration = new HttpServiceDiscoveryIntegration('test', service, {
parameterMapping: new ParameterMapping()
.overwritePath(MappingValue.custom('/$request.path.proxy'))
})

Related

How to have path based routing for AWS Application Load Balancer

I have deployed 2 services in ECS Web and API, Both of the services have their ALB, How can I configure my domain as follows:
example.com -> Web ALB
example.com/api -> API ALB
I tried creating a single ALB for both web and api target group and added a path based routing in rules but /api request is received by nodejs with full path, Eg. if a call example.com/api/products node is getting /api/products instead of /products
What could be a proper way of implementing this?
Thanks!
call example.com/api/products node is getting /api/products instead of /products
That's correct and that's how it should work. In other words, ALB can't change path from /api/products to /products, because ALB only forwards requests, it does not re-write them.
You can have a look at CloudFront, which could be helpful in that case.

How to redirect routes from cloudfront to an API Gateway that contains multiple services created by serverless framework?

I created an API Gateway using AWS CDK and I am using the serverless framework to create 3 different API's using the same API Gateway. My API Gateway structure looks like this:
/
/service1
/service1/{proxy}
/service2
/service2/{proxy}
/service3
/service3/{proxy}
I configured API Gateway as the origin of a cloudfront, redirecting requests coming from "domain/api" to API Gateway. The problem is that the path in API Gateway needs to match the selected path in cloudfront, so I would have to change it to something like:
/
/api/service1
/api/service1/{proxy}
/api/service2
/api/service2/{proxy}
/api/service3
/api/service3/{proxy}
This solution would be ok, but I can't share the "/api" path between multiple different services using the serverless framework. I would like the API Gateway rootPath to be "/api" and not "/", but I haven't been able to perform this configuration with the CDK. I wish I had something like this, is it possible?
/api
/service1
/service1/{proxy}
/service2
/service2/{proxy}
/service3
/service3/{proxy}
So that requests with /api were redirected by cloudfront to API Gateway, but could be defined as /service1 in the service, not /api/service1.

AWS API Gateway HTTP API custom domain with VPC Link to ALB

I'm trying to set up an API using a REGIONAL custom domain that routes HTTP requests to ALB.
The domain is registered with another DNS provider so I will not be using Route53.
Concept:
/path/to/service --> ALB (Listener: /path/*) --> ECS
I first tried with the original invoke URL https://cuxxxxmvk0.execute-api.ap-east-1.amazonaws.com/stage/path/to/service, it returns ALB context path error (It's expected because ALB gets /stage/path/to/service which doesn't hit any prefix).
Then I created a custom domain with API mapping (no base path) that maps to the stage, and try invoking it with the provided "API Gateway domain name" (The one generated by custom domain). Full URL: https://d-yjexxxds3.execute-api.ap-east-1.amazonaws.com/path/to/service
However, it returns {"message":"Not Found"}
API Gateway domain name
So my question here is:
How does the "API Gateway domain name" generated by custom domain works? Can I directly invoke the API with it?
Is it a must to CNAME it (i.e. CAME api.mydomain.com d-yjexxxds3.execute-api.ap-east-1.amazonaws.com)?
Can I make my final endpoint to be api.mydomain.com/path/to/service without the stage in path?
From the question I can see that you're trying to use CNAME to resolve to URL/some/path but that's not how it works. DNS service will only map your CNAME to some other URL only. The path (/some/path) part will remain same from your domain or API-GW URL.
Other thing to note here is that since you're not using Route53, you do not need Custom Domain Name of API-GW. Create a CNAME which is something like
example.com CNAME d-yjexxxds3.execute-api.ap-east-1.amazonaws.com
I would suggest you add /stage in your ALB prefix so that it can be accessed by API-GW and your own domain.
How does the "API Gateway domain name" generated by custom domain works? Can I directly invoke the API with it?
Yes, you can
Is it a must to CNAME it (i.e. CAME api.mydomain.com d-yjexxxds3.execute-api.ap-east-1.amazonaws.com)?
It is either CNAME (when the DNS is managed by an external provider) or it can be ALIAS (directly returning A records if you manage the DNS in Route53). Please note you need a validated certificate in the certificate manager.
Can I make my final endpoint to be api.mydomain.com/path/to/service without the stage in path?
https://d-xxxxxxds3.execute-api...
As far I know you should invoke the API by defined custom domain name (api.mydomain.com). If calling the d-.. domain will work, I'm not sure
https://api.mydomain.com/path/to/api
I'm not sure what is not working in your setup. Indeed in the custom domain mapping you can have a mapping directly to certain stage, so you may invoke the API as https://customdomain/path/to/api We have it working this way.
Long story short, your setup / idea is generally good. You may enable logging on the API Gateway or stage to find out what is not working (if the NOT FOUND is retuned by the API GW or backend ELB)

Default path in AWS API gateway?

We have an Rest API config in AWS API gateway where we want to route to handle a default path
/
/api
/$default (default path here)
Note we are not looking for the greedy path {proxy+}
/
/api
/{proxy+}
the problem with the greedy path is no request will route to /api ...always the {proxy+}
will take precedence even though the request has /api (tried it out)
Any help from the community in pointing us in the right direction would be of great help.
You can use the $default route to catche requests that don't explicitly match other routes in your API.
When the $default route receives a request, API Gateway sends the full request path to the integration. For example, you can create an API with only a $default route and integrate it on the ANY method with the https://petstore-demo-endpoint.execute-api.com HTTP endpoint.
When you send a request to https://api-id.execute-api.us-east-2.amazonaws.com/store/checkout, API Gateway sends a request to https://petstore-demo-endpoint.execute-api.com/store/checkout.
You can read more about it here.

How to configure $default path in AWS API gateway?

We are trying to leverage the $default path in AWS API gateway as per https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html
configured api gateway like this leveraging the $default as one of the routes
/
/-default
ANY
/api
/{proxy=}
when we are trying to invoke the api gateway on the $default path and GET call
https://apigateway.amazonaws.com/prod/test
we assumed it will invoke the default path but it didn't
message: "Missing Authentication Token"
but when we do
https://apigateway.amazonaws.com/prod/api/test
the api integration is invoked
Note : we already tried configuring greedy path{proxy+} instead of $default that does not work as the greedy path always takes precedence and /api routes also get routed to greedy path
Any help from the community in pointing us in the right direction would be of great help
It seems like you have not set up your API Gateway HTTP API routes correctly causing the routing to not work as expected. Would also like to mention that HTTP APIs and REST APIs are different types of API Gateway APIs, so do confirm that you have configured your API correctly.
Coming to how the routing would work, as a sample, here's how the routes for the API look:
Request to GET https://xxxx.execute-api.xxxx.amazonaws.com/prod/test : Routed to $default path
Request to GET https://xxxx.execute-api.xxxx.amazonaws.com/prod/api/test : Routed to /api/{proxy+} path
Further, if you have a greedy path at ANY /{proxy+}, then as you mentioned, this greedy path will take priority over the $default route. However, this would not take precedence over the ANY /api route if the request matches to the route, for example: GET https://xxxx.execute-api.xxxx.amazonaws.com/prod/api : would be routed to /api path and not /{proxy+}
The routing priority is also explained here
After selecting a stage, API Gateway selects a route. API Gateway selects the route with the most-specific match, using the following priorities:
Full match for a route and method.
Match for a route and method with a greedy path variable ({proxy+}).
The $default route.
If no routes match a request, API Gateway returns {"message":"Not Found"} to the client.
EDIT:
To create the $default route, just specify the path as $default when creating the route