

# API routing patterns
<a name="api-routing"></a>

In agile development environments, autonomous teams (for example squads and tribes) own one or more services that include many microservices. The teams expose these services as APIs to allow their consumers to interact with their group of services and actions.

There are three major methods for exposing HTTP APIs to upstream consumers by using hostnames and paths:


| 
| 
| **Method** | **Description** | **Example** | 
| --- |--- |--- |
| [**Hostname routing**](api-routing-hostname.md) | Expose each service as a hostname. | `billing.api.example.com` | 
| [**Path routing**](api-routing-path.md) | Expose each service as a path. | `api.example.com/billing` | 
| [**Header-based routing**](api-routing-http.md) | Expose each service as an HTTP header. | `x-example-action: something` | 

This section outlines typical use cases for these three routing methods and their trade-offs to help you decide which method best fits your requirements and organizational structure.

# Hostname routing pattern
<a name="api-routing-hostname"></a>

Routing by hostname is a mechanism for isolating API services by giving each API its own hostname; for example, `service-a.api.example.com` or `service-a.example.com`.

## Typical use case
<a name="hostname-use-case"></a>

Routing by using hostnames reduces the amount of friction in releases, because nothing is shared between service teams. Teams are responsible for managing everything from DNS entries to service operations in production.

![\[Hostname routing pattern to expose HTTP APIs to upstream consumers.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/images/routing-1.png)


## Pros
<a name="hostname-pros"></a>

Hostname routing is by far the most straightforward and scalable method for HTTP API routing. You can use any relevant AWS service to build an architecture that follows this method―you can create an architecture with [Amazon API Gateway](https://aws.amazon.com/api-gateway/), [AWS AppSync](https://aws.amazon.com/appsync/), [Application Load Balancers](https://aws.amazon.com/elasticloadbalancing/) and [Amazon Elastic Compute Cloud (Amazon EC2)](https://aws.amazon.com/ec2/), or any other HTTP-compliant service.

Teams can use hostname routing to fully own their subdomain. It also makes it easier to isolate, test, and orchestrate deployments for specific AWS Regions or versions; for example, `region.service-a.api.example.com` or `dev.region.service-a.api.example.com`.

## Cons
<a name="hostname-cons"></a>

When you use hostname routing, your consumers have to remember different hostnames to interact with each API that you expose. You can mitigate this issue by providing a client SDK. However, client SDKs come with their own set of challenges. For example, they have to support rolling updates, multiple languages, versioning, communicating breaking changes caused by security issues or bug fixes, documentation, and so on.

When you use hostname routing, you also need to register the subdomain or domain every time you create a new service.

# Path routing pattern
<a name="api-routing-path"></a>

Routing by paths is the mechanism of grouping multiple or all APIs under the same hostname, and using a request URI to isolate services; for example, `api.example.com/service-a` or `api.example.com/service-b`.

## Typical use case
<a name="path-routing-use-case"></a>

Most teams opt for this method because they want a simple architecture―a developer has to remember only one URL such as `api.example.com` to interact with the HTTP API. API documentation is often easier to digest because it is often kept together instead of being split across different portals or PDFs.

Path-based routing is considered a simple mechanism for sharing an HTTP API. However, it involves operational overhead such as configuration, authorization, integrations, and additional latency due to multiple hops. It also requires mature change management processes to ensure that a misconfiguration doesn't disrupt all services.

On AWS, there are multiple ways to share an API and route effectively to the correct service. The following sections discuss three approaches: HTTP service reverse proxy, API Gateway, and Amazon CloudFront. None of the suggested approaches for unifying API services relies on the downstream services running on AWS. The services could run anywhere without issue or on any technology, as long as they're HTTP-compatible.

## HTTP service reverse proxy
<a name="path-routing-proxy"></a>

You can use an HTTP server such as [NGINX](https://www.f5.com/go/product/welcome-to-nginx) to create dynamic routing configurations. In a [Kubernetes](https://kubernetes.io/) architecture, you can also create an ingress rule to match a path to a service. (This guide doesn't cover Kubernetes ingress; see the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/#the-ingress-resource) for more information.)

The following configuration for NGINX dynamically maps an HTTP request of `api.example.com/my-service/` to `my-service.internal.api.example.com`.

```
server {
    listen  80;

    location (^/[\w-]+)/(.*) {
        proxy_pass $scheme://$1.internal.api.example.com/$2;
    }
}
```

The following diagram illustrates the HTTP service reverse proxy method.



![\[Using an HTTP service reverse proxy for path routing.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/images/routing-2.png)


This approach might be sufficient for some use cases that don't use additional configurations to start processing requests, allowing for the downstream API to collect metrics and logs.

To get ready for operational production readiness, you will want to be able to add observability to every level of your stack, add additional configuration, or add scripts to customize your API ingress point to allow for more advanced features such as rate limiting or usage tokens.

### Pros
<a name="path-routing-proxy-pros"></a>

The ultimate aim of the HTTP service reverse proxy method is to create a scalable and manageable approach to unifying APIs into a single domain so it appears coherent to any API consumer. This approach also enables your service teams to deploy and manage their own APIs, with minimal overhead after deployment. AWS managed services for tracing, such as [AWS X-Ray](https://aws.amazon.com/xray/) or [AWS WAF](https://aws.amazon.com/waf/), are still applicable here.

### Cons
<a name="path-routing-proxy-cons"></a>

The major downside of this approach is the extensive testing and management of infrastructure components that are required, although this might not be an issue if you have site reliability engineering (SRE) teams in place.

There is a cost tipping point with this method. At low to medium volumes, it is more expensive than some of the other methods discussed in this guide. At high volumes, it is very cost-effective (around 100K transactions per second or better).

## API Gateway
<a name="path-routing-gateway"></a>

The [Amazon API Gateway](https://aws.amazon.com/api-gateway/) service (REST APIs and HTTP APIs) can route traffic in a way that's similar to the HTTP service reverse proxy method. Using an API gateway in HTTP proxy mode provides a simple way to wrap many services into an entry point to the top-level subdomain `api.example.com`, and then proxy requests to the nested service; for example, `billing.internal.api.example.com`.

You probably don't want to get too granular by mapping every path in every service in the root or core API gateway. Instead, opt for wildcard paths such as `/billing/*` to forward requests to the billing service. By not mapping every path in the root or core API gateway, you gain more flexibility over your APIs, because you don't have to update the root API gateway with every API change.

![\[Path routing through API Gateway.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/images/routing-3.png)


### Pros
<a name="path-routing-gateway-pros"></a>

For control over more complex workflows, such as changing request attributes, REST APIs expose the Apache Velocity Template Language (VTL) to allow you to modify the request and response. REST APIs can provide additional benefits such as these:
+ [Auth N/Z with AWS Identity and Access Management (IAM),](https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-net-applications-security/authentication.html) [Amazon Cognito](https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-net-applications-security/cognito.html), or [AWS Lambda authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)
+ [AWS X-Ray for tracing](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-understanding-xray-traces.html)
+ [Integration with AWS WAF](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-control-access-aws-waf.html)
+ [Basic rate limiting](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html)
+ Usage tokens for bucketing consumers into different tiers (see [Throttle API requests for better throughput](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html) in the API Gateway documentation)

### Cons
<a name="path-routing-gateway-cons"></a>

At high volumes, cost might be an issue for some users.

## CloudFront
<a name="path-routing-cloudfront"></a>

You can use the [dynamic origin selection feature](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html) in [Amazon CloudFront](https://aws.amazon.com/cloudfront/) to conditionally select an origin (a service) to forward the request. You can use this feature to route a number of services through a single hostname such as `api.example.com`.

### Typical use case
<a name="path-routing-cloudfront-usecase"></a>

The routing logic lives as code within the Lambda@Edge function, so it supports highly customizable routing mechanisms such as A/B testing, canary releases, feature flagging, and path rewriting. This is illustrated in the following diagram.

![\[Path routing through CloudFront.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/images/routing-4.png)


### Pros
<a name="path-routing-cloudfront-pros"></a>

If you require caching API responses, this method is good way to unify a collection of services behind a single endpoint. It is a cost-effective method to unify collections of APIs.

Also, CloudFront supports [field-level encryption](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/field-level-encryption.html) as well as integration with AWS WAF for basic rate limiting and basic ACLs.

### Cons
<a name="path-routing-cloudfront-cons"></a>

This method supports a maximum of 250 origins (services) that can be unified. This limit is sufficient for most deployments, but it might cause issues with a large number of APIs as you grow your portfolio of services.

Updating Lambda@Edge functions currently takes a few minutes. CloudFront also takes up to 30 minutes to complete propagating changes to all points of presence. This ultimately blocks further updates until they complete.

# HTTP header routing pattern
<a name="api-routing-http"></a>

Header-based routing enables you to target the correct service for each request by specifying an HTTP header in the HTTP request. For example, sending the header `x-service-a-action: get-thing` would enable you to `get thing` from `Service A`. The path of the request is still important, because it offers guidance on which resource you're trying to work on.

In addition to using HTTP header routing for actions, you can use it as a mechanism for version routing, enabling feature flags, A/B tests, or similar needs. In reality, you will likely use header routing with one of the other routing methods to create robust APIs.

The architecture for HTTP header routing typically has a thin routing layer in front of microservices that routes to the correct service and returns a response, as illustrated in the following diagram. This routing layer could cover all services or just a few services to enable an operation such as version-based routing.

![\[HTTP header routing.\]](http://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/images/routing-5.png)


## Pros
<a name="path-routing-http-pros"></a>

Configuration changes require minimal effort and can be automated easily. This method is also flexible and supports creative ways to expose only specific operations you would want from a service.

## Cons
<a name="path-routing-http-cons"></a>

As with the hostname routing method, HTTP header routing assumes that you have full control over the client and can manipulate custom HTTP headers. Proxies, content delivery networks (CDNs), and load balancers can limit the header size. Although this is unlikely to be a concern, it could be an issue depending on how many headers and cookies you add.