Implementing API Gateway Patterns
1. Routing API Requests
| Directive | Description | Example |
|---|---|---|
| location | Defines how to handle requests based on URI | location /api/ { proxy_pass http://backend; } |
| proxy_pass | Specifies the backend server to forward requests to | proxy_pass http://upstream_backend; |
| rewrite | Modifies the URI before forwarding | rewrite ^/api/(.*)$ /$1 break; |
Example: Basic API Route
server {
listen 80;
location /api/users {
proxy_pass http://user_service;
}
}
Example: Rewrite and Forward
location /api/v1/ {
rewrite ^/api/v1/(.*)$ /v1/$1 break;
proxy_pass http://backend_v1;
}
Note: The
location block matches the URI path and can use regex patterns or prefix matching.
2. Implementing API Versioning
| Version Strategy | Description | Implementation |
|---|---|---|
| URL Path Versioning | Version specified in the URL path (e.g., /api/v1/users) | |
| Header Versioning | Version specified in a custom header (e.g., X-API-Version) | |
| Query Parameter Versioning | Version specified as a query parameter (e.g., /api/users?version=v1) | |
Example: URL Path Versioning
server {
listen 80;
server_name example.com;
location /api/v1/users {
proxy_pass http://backend_v1;
}
location /api/v2/users {
proxy_pass http://backend_v2;
}
}
Note: URL path versioning is the most commonly used and recommended method for API versioning in Nginx.
3. Rate Limiting API Endpoints
| Directive | Description | Values | Notes |
|---|---|---|---|
| limit_req_zone | Defines a shared memory zone for storing rate limit state | zone=name:size, rate=rate |
Required for rate limiting configuration |
| limit_req | Applies rate limiting to a location or server block | zone=name, burst=number, nodelay |
Enables rate limiting based on the zone defined |
Example: Basic Rate Limiting Configuration
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/m;
server {
listen 80;
location /api/ {
limit_req zone=api burst=5 nodelay;
proxy_pass http://backend;
}
}
}
Example: Rate Limiting with Burst and Delay
http {
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/m;
server {
listen 80;
location /api/ {
limit_req zone=api burst=10 nodelay;
proxy_pass http://backend;
}
}
}
Note: The
rate parameter is in requests per second (r/s) or per minute (r/m). For example, rate=10r/m allows 10 requests per minute.
Warning: If
nodelay is not specified, burst requests will be delayed until the rate limit allows them.
Rate Limiting Configuration Summary
limit_req_zonecreates a shared memory zone to track rate limits.limit_reqapplies the rate limit to specific locations or servers.- Burst allows temporary overuse of the rate limit without delay.
- Use
nodelayto avoid delays for burst requests.
4. Authenticating API Requests
| Directive | Description | Example |
|---|---|---|
| auth_jwt | Enables JWT-based authentication for API requests. | auth_jwt "API" token=$jwt_token; |
| auth_jwt_key_file | Specifies the file containing the public key for JWT verification. | auth_jwt_key_file /etc/nginx/jwt_keys/public.key; |
| auth_jwt_claim | Defines the claim to be used for authentication (e.g., sub, aud). |
auth_jwt_claim sub; |
Example: JWT Authentication Setup
location /api/ {
auth_jwt "API";
auth_jwt_key_file /etc/nginx/jwt_keys/public.key;
proxy_pass http://backend;
}
Note: Ensure the JWT token is passed in the
Authorization header as Bearer <token>.
| Claim | Description | Required |
|---|---|---|
| sub | Subject identifier (e.g., user ID or client ID). | Yes |
| aud | Audience claim to verify the token is intended for this API. | Yes |
| exp | Expiration time of the token. | Yes |
| iss | Issuer of the token (e.g., identity provider). | No |
5. Implementing API Key Validation
| Directive | Description | Example |
|---|---|---|
| auth_jwt | Enables JWT-based authentication for API requests | auth_jwt "API Gateway" token=$jwt_token; |
| auth_jwt_key_file | Specifies the file containing public keys for JWT validation | auth_jwt_key_file /etc/nginx/jwt-keys.pem; |
| auth_jwt_claim | Defines the claim to extract from the JWT for validation | auth_jwt_claim api_key $jwt_api_key; |
Example: Basic API Key Validation Setup
server {
listen 80;
server_name api.example.com;
location /api/ {
auth_jwt "API Gateway";
auth_jwt_key_file /etc/nginx/jwt-keys.pem;
auth_jwt_claim api_key $jwt_api_key;
proxy_pass http://backend;
}
}
Example: Validating API Key from Header
server {
listen 443 ssl;
server_name api.example.com;
location /api/v1/ {
auth_jwt "API Gateway";
auth_jwt_key_file /etc/nginx/jwt-keys.pem;
# Extract API key from Authorization header
auth_jwt_claim api_key $jwt_api_key;
proxy_pass http://backend;
}
}
Note: Ensure that the JWT keys are securely stored and only accessible to the Nginx process.
6. Configuring Request Transformation
| Directive | Description | Example |
|---|---|---|
| proxy_set | Sets a header to be sent to the upstream server | proxy_set X-Forwarded-For $proxy_add_x_forwarded_for; |
| proxy_hide_header | Hides a header from the response | proxy_hide_header X-Powered-By; |
| proxy_pass_request_headers | Controls whether request headers are passed to the upstream server | proxy_pass_request_headers on; |
Example: Transforming Request Headers
location /api/ {
proxy_pass http://backend;
proxy_set X-Original-URI $request_uri;
proxy_hide_header Server;
}
Note: Use
proxy_set to modify or add headers, and proxy_hide_header to remove them before forwarding the request.
7. Implementing Response Transformation
| Directive | Description | Example |
|---|---|---|
| proxy_hide_header | Hides a response header from the client | proxy_hide_header X-Powered-By; |
| proxy_set_header | Sets a header to be sent to the upstream server | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| proxy_pass | Specifies the address of the upstream server | proxy_pass http://backend; |
| rewrite | Modifies the URI of a request | rewrite ^/api/(.*)$ /$1 break; |
Example: Transforming Response Headers
location /api/ {
proxy_pass http://backend;
proxy_hide_header X-Powered-By;
proxy_set_header X-Forwarded-Proto $scheme;
}
Example: Rewriting URI for Response Transformation
location /api/v1/ {
rewrite ^/api/v1/(.*)$ /v2/$1 break;
proxy_pass http://backend;
}
Note: Response transformation directives like
rewrite and proxy_set_header can be used to modify the response before it reaches the client.
8. Handling CORS for APIs
| Directive | Description | Example |
|---|---|---|
| add_header | Adds custom headers to the response | add_header Access-Control-Allow-Origin *; |
| add_header | Allows specific headers in preflight requests | add_header Access-Control-Allow-Headers "Content-Type, Authorization"; |
| add_header | Specifies allowed HTTP methods | add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE"; |
Example: Basic CORS Configuration
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
proxy_pass http://backend;
}
Note: Using
* for Access-Control-Allow-Origin allows any domain to access the API. For production, specify domains explicitly.
Example: Handling Preflight Requests
location /api/ {
if ($request_method = "OPTIONS") {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
add_header Access-Control-Max-Age 86400;
return 204;
}
proxy_pass http://backend;
}
9. Implementing Request Routing by Header
| Directive | Description | Example |
|---|---|---|
| location | Defines a location block to match requests based on URI or header | location /api/ { ... } |
| if | Conditionally routes requests based on header values | if ($http_user_agent ~* "Mobile") { ... } |
| map | Maps header values to variables for use in routing logic | map $http_user_agent $mobile { default 0; ~* "Mobile" 1; } |
Example: Route by User-Agent Header
server {
listen 80;
location /api/ {
if ($http_user_agent ~* "Mobile") {
proxy_pass http://mobile_backend;
}
if ($http_user_agent ~* "Desktop") {
proxy_pass http://desktop_backend;
}
proxy_pass http://default_backend;
}
}
Example: Using Map for Header-Based Routing
http {
map $http_user_agent $backend {
default "default_backend";
~* "Mobile" "mobile_backend";
~* "Desktop" "desktop_backend";
}
server {
listen 80;
location /api/ {
proxy_pass http://$backend;
}
}
}
Note: The
if directive can lead to performance issues and is generally discouraged in favor of map or location blocks for routing logic.
10. Using Upstream Groups for Microservices
| Directive | Description | Example |
|---|---|---|
| upstream | Defines a group of servers (upstreams) to which requests can be forwarded | |
| server | Defines a server within an upstream block | server 192.168.1.10:8080 weight=3; |
| keepalive | Enables persistent connections to upstream servers | keepalive 32; |
Example: Load Balancing with Upstream Groups
upstream api_backend {
server 127.0.0.1:8080 weight=3;
server 127.0.0.1:8081 weight=2;
server 127.0.0.1:8082 backup;
}
server {
listen 80;
location /api/ {
proxy_pass http://api_backend/;
}
}
Note: The
weight parameter controls how many requests each server receives. Servers marked as backup only receive traffic when all other servers are unavailable.
Upstream Group Configuration Summary
- upstream defines a group of backend servers
- server specifies individual servers with optional parameters
- weight allows for weighted load balancing
- backup designates failover servers
- keepalive enables persistent connections to upstreams
11. Implementing Circuit Breaker
| Directive | Description | Default | Notes |
|---|---|---|---|
| circuit_breaker | Enables circuit breaker logic for upstream servers | Off | Requires ngx_http_upstream_module |
| circuit_breaker_error_codes | Defines error codes that trigger circuit breaker | 500, 502, 503, 504 | Can be extended with custom codes |
| circuit_breaker_timeout | Timeout for circuit breaker logic | 30s | Used to reset circuit state |
Example: Basic Circuit Breaker Configuration
upstream api_backend {
server 192.168.1.10:8080;
server 192.168.1.11:8080;
# Enable circuit breaker
circuit_breaker error_codes=500,502,503,504 timeout=30s;
}
server {
listen 80;
location /api/ {
proxy_pass http://api_backend;
}
}
Note: The circuit breaker will trip if the specified error codes are returned more than a defined threshold within a given time window.
Warning: Ensure that the
circuit_breaker directive is used in conjunction with proper error handling to avoid unexpected behavior.
Key Features of Circuit Breaker in Nginx
- Triggers on specific HTTP error codes (500, 502, 503, 504 by default)
- Automatically resets after a timeout period
- Prevents cascading failures in API gateways
12. Logging API Metrics
| Directive | Description | Example |
|---|---|---|
| access_log | Defines the file to which access logs are written | access_log /var/log/nginx/access.log; |
| error_log | Defines the file to which error logs are written | error_log /var/log/nginx/error.log; |
| log_format | Defines custom log formats for access logs | log_format main '$remote_addr - $remote_user [$time_local] "$request" ...'; |
Example: Custom Log Format for API Metrics
log_format api_metrics '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" $request_time';
Example: Using Custom Log Format
server {
listen 80;
location /api/ {
access_log /var/log/nginx/api_access.log api_metrics;
proxy_pass http://backend;
}
}
Note: The
$request_time variable includes the time taken to process the request, useful for performance monitoring.