Swiftorial Logo
Home
Swift Lessons
Tutorials
Learn More
Career
Resources

API Gateway with Microservices

Introduction to API Gateway Architecture

The API Gateway architecture serves as a robust and centralized entry point for managing client requests to a microservices ecosystem, ensuring secure, scalable, and observable interactions. It handles critical cross-cutting concerns such as Authentication (via OAuth2/JWT), Authorization (via Role-Based Access Control or RBAC), Rate Limiting, Service Discovery, and Monitoring. By routing requests to independently deployed microservices (e.g., Order, Payment, Inventory), the gateway abstracts service complexity from clients, enhances security through token validation, and supports dynamic scaling. The system integrates Consul for service discovery, Redis for distributed rate limiting, and Prometheus with Grafana for comprehensive observability, making it ideal for modern, distributed applications.

The API Gateway simplifies client interactions by centralizing security, routing, and monitoring, while microservices maintain independence for scalability and resilience.

Architecture Diagram

The diagram illustrates the API Gateway architecture: Clients (web, mobile, or IoT) authenticate with an Auth Server to obtain OAuth2/JWT tokens. The API Gateway validates these tokens and routes requests to microservices (Order, Payment, Inventory), each enforcing RBAC for fine-grained authorization. The gateway leverages Service Discovery (Consul) to locate healthy service instances dynamically and applies Rate Limiting to prevent overload. Metrics are collected and sent to a Monitoring System (Prometheus/Grafana) for real-time insights. Arrows are color-coded: yellow (dashed) for client traffic, orange-red for authenticated service routing, blue (dotted) for service discovery interactions, and purple for monitoring data flows.

graph TD A[Client] -->|Login Request| B[Auth Server: OAuth2/JWT] B -->|Issues JWT| A A -->|Client Traffic with JWT| C[API Gateway] C -->|Validates JWT| B C -->|Rate Limiting| C C -->|Routes| D[Order Service: RBAC] C -->|Routes| E[Payment Service: RBAC] C -->|Routes| F[Inventory Service: RBAC] C -->|Queries| G[Service Discovery: Consul] G -->|Locates| D G -->|Locates| E G -->|Locates| F C -->|Metrics| H[Monitoring: Prometheus] D -->|Metrics| H E -->|Metrics| H F -->|Metrics| H subgraph Authentication Layer B C end subgraph Microservices Layer D E F G end subgraph Monitoring Layer H end classDef client fill:#ffeb3b,stroke:#ffeb3b,stroke-width:2px,rx:10,ry:10; classDef gateway fill:#ff6f61,stroke:#ff6f61,stroke-width:2px,rx:10,ry:10; classDef service fill:#405de6,stroke:#405de6,stroke-width:2px,rx:5,ry:5; classDef discovery fill:#2ecc71,stroke:#2ecc71,stroke-width:2px; classDef monitoring fill:#9b59b6,stroke:#9b59b6,stroke-width:2px; class A client; class B,C gateway; class D,E,F service; class G discovery; class H monitoring; linkStyle 0,1 stroke:#ff6f61,stroke-width:2.5px linkStyle 2 stroke:#ffeb3b,stroke-width:2.5px,stroke-dasharray:6,6 linkStyle 3,4,5,6,7 stroke:#ff6f61,stroke-width:2.5px linkStyle 8,9,10 stroke:#2ecc71,stroke-width:2.5px,stroke-dasharray:4,4 linkStyle 11,12,13,14 stroke:#9b59b6,stroke-width:2.5px
The API Gateway ensures secure and efficient routing with JWT validation and rate limiting, while Consul enables dynamic service discovery for resilient microservices.

Key Components

The architecture is built on a set of interconnected components designed to deliver secure, scalable, and observable microservices:

  • Client: Web, mobile, or IoT devices sending HTTP requests to the API Gateway.
  • Auth Server: Implements OAuth2/JWT for issuing and validating tokens (e.g., Keycloak, Auth0).
  • API Gateway: Centralizes routing, JWT validation, rate limiting, and metrics collection (e.g., Kong, AWS API Gateway).
  • Microservices (Order, Payment, Inventory): Independently deployed services with RBAC for fine-grained access control.
  • Service Discovery: Dynamically locates service instances using Consul or Eureka, ensuring load balancing and fault tolerance.
  • Rate Limiting: Enforces request quotas per client using Redis for distributed state management.
  • Monitoring: Collects metrics with Prometheus and visualizes them in Grafana for system health and performance insights.
  • Security Layer: Combines JWT-based authentication, RBAC authorization, and mTLS for inter-service communication.

Benefits of the Architecture

The API Gateway with microservices architecture offers significant advantages for modern distributed systems:

  • Enhanced Security: OAuth2/JWT ensures secure authentication, while RBAC provides granular authorization at the service level.
  • High Scalability: Microservices scale independently, with the gateway distributing traffic based on service discovery.
  • Improved Resilience: Service discovery routes requests to healthy instances, and circuit breakers prevent cascading failures.
  • Optimized Performance: Rate limiting and caching reduce service overload and latency.
  • Comprehensive Observability: Prometheus and Grafana provide real-time insights into API usage, errors, and system health.
  • Development Agility: Independent microservices enable teams to develop, deploy, and update services without system-wide disruptions.
  • Client Simplicity: The API Gateway abstracts service complexity, providing a unified interface for clients.

Implementation Considerations

Building a secure and scalable API Gateway with microservices requires careful planning across multiple dimensions:

  • Authentication Setup: Deploy an auth server (e.g., Keycloak) with short-lived JWT tokens and refresh tokens for secure client access.
  • Authorization Design: Implement RBAC in each microservice, defining roles (e.g., admin, user) and mapping them to specific endpoints.
  • API Gateway Configuration: Use Kong or AWS API Gateway with plugins for JWT validation, rate limiting, and metrics export to Prometheus.
  • Service Discovery Integration: Deploy Consul with health checks and mTLS to dynamically locate and secure service instances.
  • Rate Limiting Strategy: Implement token bucket algorithms in Redis, tailoring limits per client, endpoint, or user role to prevent abuse.
  • Monitoring and Observability: Configure Prometheus to scrape metrics from the gateway and services, with Grafana dashboards for visualizing latency, error rates, and traffic patterns.
  • Security Hardening: Enforce mTLS for inter-service communication, use AES-256 encryption for sensitive data, and regularly rotate JWT secrets.
  • Load Balancing: Configure the gateway to distribute traffic across service instances based on Consul’s health checks.
  • Error Handling: Implement circuit breakers and retries in the gateway to handle transient service failures gracefully.
  • Testing and Validation: Conduct load testing for rate limiting, penetration testing for security, and chaos testing to ensure resilience.
Regular security audits, performance tuning for rate limiting, and health checks for service discovery are critical to maintaining a secure and reliable system.

Example Configuration: Kong API Gateway with JWT and Rate Limiting

Below is a detailed Kong configuration for securing and routing requests to a microservice with JWT validation, rate limiting, and Prometheus monitoring:

# Define a service in Kong
curl -i -X POST http://kong:8001/services \
  --data name=order-service \
  --data url=https://order-service:3000

# Define a route for the order service
curl -i -X POST http://kong:8001/services/order-service/routes \
  --data 'paths[]=/orders' \
  --data methods[]=GET \
  --data methods[]=POST

# Enable JWT plugin for authentication
curl -i -X POST http://kong:8001/services/order-service/plugins \
  --data name=jwt \
  --data config.key_claim_name=iss \
  --data config.secret_is_base64=false

# Enable rate-limiting plugin with Redis
curl -i -X POST http://kong:8001/services/order-service/plugins \
  --data name=rate-limiting \
  --data config.second=5 \
  --data config.hour=1000 \
  --data config.policy=redis \
  --data config.redis_host=redis-host \
  --data config.redis_port=6379 \
  --data config.redis_timeout=1000

# Enable Prometheus plugin for monitoring
curl -i -X POST http://kong:8001/plugins \
  --data name=prometheus \
  --data config.per_consumer=true
                

Example Configuration: Order Service with RBAC and mTLS

Below is a Node.js implementation of an Order Service with RBAC for role-based authorization and mTLS for secure communication:

const express = require('express');
const jwt = require('jsonwebtoken');
const https = require('https');
const fs = require('fs');

const app = express();
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';

// mTLS configuration for secure inter-service communication
const serverOptions = {
  key: fs.readFileSync('server-key.pem'),
  cert: fs.readFileSync('server-cert.pem'),
  ca: fs.readFileSync('ca-cert.pem'),
  requestCert: true,
  rejectUnauthorized: true
};

// Middleware for RBAC
const checkRBAC = (requiredRole) => (req, res, next) => {
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ error: 'Unauthorized: Missing or invalid token' });
    }

    const token = authHeader.split(' ')[1];
    try {
        const decoded = jwt.verify(token, JWT_SECRET);
        if (!decoded.role || decoded.role !== requiredRole) {
            return res.status(403).json({ error: `Insufficient permissions: ${requiredRole} role required` });
        }
        req.user = decoded;
        next();
    } catch (err) {
        return res.status(403).json({ error: 'Invalid token' });
    }
};

// Endpoint to retrieve orders (admin-only)
app.get('/orders', checkRBAC('admin'), async (req, res) => {
    try {
        const orders = await db.query('SELECT * FROM orders'); // Mock database query
        res.json({ orders, user: req.user });
    } catch (err) {
        res.status(500).json({ error: 'Failed to retrieve orders' });
    }
});

// Endpoint to create an order (user or admin)
app.post('/orders', checkRBAC('user'), async (req, res) => {
    try {
        const order = req.body;
        const result = await db.insert('orders', order); // Mock database insert
        res.status(201).json({ orderId: result.id });
    } catch (err) {
        res.status(500).json({ error: 'Failed to create order' });
    }
});

https.createServer(serverOptions, app).listen(3000, () => {
    console.log('Order Service running on port 3000 with mTLS');
});
                

Example Configuration: Consul Service Discovery

Below is a configuration for Consul to enable dynamic service discovery and health checks for microservices:

# Register Order Service with Consul
curl -X PUT http://consul:8500/v1/agent/service/register \
  -H 'Content-Type: application/json' \
  -d '{
    "ID": "order-service-1",
    "Name": "order-service",
    "Address": "order-service",
    "Port": 3000,
    "Tags": ["microservice", "orders"],
    "Check": {
      "HTTP": "https://order-service:3000/health",
      "Interval": "10s",
      "Timeout": "2s",
      "TLSSkipVerify": false
    }
  }'

# Query Consul for service instances
curl http://consul:8500/v1/catalog/service/order-service

# Enable mTLS for Consul communication
curl -X PUT http://consul:8500/v1/agent/connect/ca \
  -H 'Content-Type: application/json' \
  -d '{
    "Provider": "consul",
    "Config": {
      "LeafCertTTL": "72h",
      "IntermediateCertTTL": "8760h"
    }
  }'