Skip to main content
⚡ Calmops

API Gateway and Management: Design, Security, and Best Practices

Introduction

APIs are the backbone of modern applications, enabling communication between services, powering mobile and web applications, and facilitating integration with external systems. API gateways serve as the single entry point for API traffic, providing security, monitoring, and management capabilities.

Effective API management is crucial for maintaining secure, performant, and well-documented APIs. As organizations expose more APIs—both internally and externally—managing them effectively becomes essential for developer productivity and security.

This comprehensive guide examines API gateway and management concepts. We explore gateway architecture, security patterns, authentication mechanisms, rate limiting, and monitoring strategies. Whether building your first API or establishing enterprise API management, this guide provides the knowledge necessary for success.

Understanding API Gateways

An API gateway sits between clients and backend services, handling requests and routing them to appropriate backend services.

Gateway Functions

  • Request Routing: Direct requests to appropriate backend services
  • Authentication: Verify client credentials and authorize access
  • Rate Limiting: Control request rates to protect backends
  • Protocol Translation: Convert between client and backend protocols
  • Response Transformation: Modify responses as needed
  • Monitoring: Track API usage and performance

Architecture Patterns

graph TB
    Client[Client Apps/Mobile/Web] --> Gateway[API Gateway]
    Gateway --> Auth[Authentication Service]
    Gateway --> RateLimiter[Rate Limiter]
    Gateway --> Backend1[User Service]
    Gateway --> Backend2[Order Service]
    Gateway --> Backend3[Product Service]
    Gateway --> Mon[Monitoring/Logging]

AWS API Gateway

AWS API Gateway provides fully managed API management.

REST API Configuration

# Terraform - API Gateway REST API
resource "aws_api_gateway_rest_api" "main" {
  name        = "main-api"
  description = "Main API"
  
  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_resource" "users" {
  rest_api_id = aws_api_gateway_rest_api.main.id
  parent_id   = aws_api_gateway_rest_api.main.root_resource_id
  path_part  = "users"
}

resource "aws_api_gateway_method" "get_users" {
  rest_api_id   = aws_api_gateway_rest_api.main.id
  resource_id   = aws_api_gateway_resource.users.id
  http_method   = "GET"
  authorization = "NONE"
}

resource "aws_api_gateway_integration" "lambda" {
  rest_api_id = aws_api_gateway_rest_api.main.id
  resource_id = aws_api_gateway_resource.users.id
  http_method = aws_api_gateway_method.get_users.http_method
  
  type                    = "AWS_PROXY"
  uri                     = aws_lambda_function.users.invoke_arn
  integration_http_method = "POST"
}

HTTP API (v2)

# API Gateway HTTP API
resource "aws_api_gatewayv2_api" "main" {
  name          = "main-http-api"
  protocol_type = "HTTP"
}

resource "aws_api_gatewayv2_route" "users" {
  api_id    = aws_api_gatewayv2_api.main.id
  route_key = "GET /users"
  
  target = "integrations/${aws_api_gatewayv2_integration.users.id}"
}

resource "aws_api_gatewayv2_integration" "users" {
  api_id           = aws_api_gatewayv2_api.main.id
  integration_type = "AWS_PROXY"
  integration_uri  = aws_lambda_function.users.invoke_arn
}

Custom Domain

# Custom domain configuration
resource "aws_api_gateway_domain_name" "api" {
  domain_name = "api.example.com"
  
  certificate_arn = aws_acm_certificate.cert.arn
  
  endpoint_configuration {
    types = ["REGIONAL"]
  }
}

resource "aws_api_gateway_base_path_mapping" "api" {
  api_id      = aws_api_gateway_rest_api.main.id
  domain_name = aws_api_gateway_domain_name.api.domain_name
}

Azure API Management

Azure API Management provides comprehensive API management capabilities.

API Management Configuration

# Create API Management instance
New-AzApiManagement `
    -Name "api-management" `
    -ResourceGroupName "rg-api" `
    -Location "East US" `
    -Organization "Example Corp" `
    -AdminEmail "[email protected]" `
    -SkuType "Developer"

# Add API
$api = @{
    Name = "users-api"
    DisplayName = "Users API"
    Description = "User management API"
    Path = "users"
    Protocol = @("https")
    BackendUrl = "https://api.example.com"
}

New-AzApiManagementApi @api

Policy Configuration

<!-- Rate limiting policy -->
<policies>
    <inbound>
        <!-- Validate JWT -->
        <validate-jwt header-name="Authorization">
            <openid-config url="https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration" />
            <audiences>
                <audience>api://myapi</audience>
            </audiences>
        </validate-jwt>
        
        <!-- Rate limiting -->
        <rate-limit-by-key calls="100" renewal-period="60" counter-key="@(context.Request.IpAddress)" />
        
        <!-- CORS -->
        <cors>
            <allowed-origins>
                <origin>https://example.com</origin>
            </allowed-origins>
            <allowed-methods>
                <method>GET</method>
                <method>POST</method>
                <method>PUT</method>
                <method>DELETE</method>
            </allowed-methods>
        </cors>
    </inbound>
    
    <backend>
        <forward-request />
    </backend>
    
    <outbound>
        <!-- Response transformation -->
        <set-header name="X-API-Version" exists-action="override">
            <value>1.0</value>
        </set-header>
    </outbound>
</policies>

API Security

Securing APIs is paramount. Multiple layers of security should be implemented.

Authentication Mechanisms

# API Key authentication
resource "aws_api_gateway_api_key" "main" {
  name = "main-api-key"
}

resource "aws_api_gateway_usage_plan" "main" {
  name = "main-usage-plan"
  
  api_stages {
    api_id = aws_api_gateway_rest_api.main.id
    stage  = aws_api_gateway_stage.prod.stage_name
  }
  
  quota_settings {
    limit  = 1000000
    period = "MONTH"
  }
  
  throttle_settings {
    burst_limit = 5000
    rate_limit  = 1000
  }
}

resource "aws_api_gateway_usage_plan_key" "main" {
  key_id        = aws_api_gateway_api_key.main.id
  key_type     = "API_KEY"
  usage_plan_id = aws_api_usage_plan.main.id
}

JWT Validation

// JWT validation in Lambda authorizer
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
  jwksUri: 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxx/.well-known/jwks.json'
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

exports.handler = async (event) => {
  const token = event.authorizationToken;
  
  try {
    const decoded = await new Promise((resolve, reject) => {
      jwt.verify(token, getKey, {
        issuer: 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxx',
        audience: 'api://myapi'
      }, (err, decoded) => {
        if (err) reject(err);
        else resolve(decoded);
      });
    });
    
    return {
      principalId: decoded.sub,
      policyDocument: {
        Version: '2012-10-17',
        Statement: [{
          Action: 'execute-api:Invoke',
          Effect: 'Allow',
          Resource: event.methodArn
        }]
      }
    };
  } catch (err) {
    return {
      principalId: 'unauthorized',
      policyDocument: {
        Version: '2012-10-17',
        Statement: [{
          Action: 'execute-api:Invoke',
          Effect: 'Deny',
          Resource: event.methodArn
        }]
      }
    };
  }
};

OAuth 2.0 Integration

# OAuth 2.0 authorizer
resource "aws_api_gateway_authorizer" "oauth" {
  name                   = "oauth-authorizer"
  rest_api_id           = aws_api_gateway_rest_api.main.id
  authorizer_uri        = "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${aws_lambda_function.oauth_authorizer.arn}/invocations"
  authorizer_credentials = aws_iam_role.api_authorizer.arn
  type                  = "TOKEN"
  identity_source       = "method.request.header.Authorization"
  
  provider_arns = ["arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_xxxxx"]
}

Rate Limiting

Protecting backends from overload through rate limiting.

API Gateway Throttling

# Usage plan with throttling
resource "aws_api_gateway_usage_plan" "tiered" {
  name = "tiered-usage-plan"
  
  tiered {
    api_stage {
      api_id = aws_api_gateway_rest_api.main.id
      stage  = aws_api_gateway_stage.prod.stage_name
    }
    
    price_class = "Tiered"
  }
  
  # Free tier
  quota_settings {
    limit  = 10000
    period = "MONTH"
  }
  
  # Standard tier
  throttle_settings {
    burst_limit = 100
    rate_limit = 50
  }
}

Custom Rate Limiting with Lambda

// DynamoDB-based rate limiter
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB.DocumentClient();

const TABLE_NAME = 'rate-limits';

async function checkRateLimit(clientId, limit, window) {
    const now = Date.now();
    const windowStart = now - window;
    
    // Get current count
    const result = await dynamodb.get({
        TableName: TABLE_NAME,
        Key: { clientId }
    }).promise();
    
    const item = result.Item;
    if (!item || item.windowStart < windowStart) {
        // New window
        await dynamodb.put({
            TableName: TABLE_NAME,
            Item: {
                clientId,
                count: 1,
                windowStart: now
            }
        }).promise();
        return { allowed: true, remaining: limit - 1 };
    }
    
    if (item.count >= limit) {
        return { allowed: false, remaining: 0, retryAfter: item.windowStart + window - now };
    }
    
    // Increment counter
    await dynamodb.update({
        TableName: TABLE_NAME,
        Key: { clientId },
        UpdateExpression: 'SET #count = #count + :inc',
        ExpressionAttributeNames: { '#count': 'count' },
        ExpressionAttributeValues: { ':inc': 1 }
    }).promise();
    
    return { allowed: true, remaining: limit - item.count - 1 };
}

GraphQL API Management

GraphQL requires different management approaches than REST.

# AWS AppSync GraphQL API
resource "aws_appsync_graphql_api" "main" {
  name           = "main-graphql-api"
  authentication_type = "API_KEY"
  
  schema = file("schema.graphql")
  
  additional_authentication_providers {
    authentication_type = "AMAZON_COGNITO_USER_POOLS"
    cognito_user_pool_config {
      user_pool_id = aws_cognito_user_pool.main.id
    }
  }
}
# GraphQL schema with rate limiting
type Query {
    users(limit: Int): [User!]!
    user(id: ID!): User
}

type Mutation {
    createUser(input: CreateUserInput!): User!
}

directive @rateLimit(
    limit: Int,
    window: String
) on FIELD_DEFINITION

type User @model @auth(rules: [{ allow: owner }]) {
    id: ID!
    name: String!
    email: AWSEmail!
}

API Documentation

Well-documented APIs enable developer productivity.

OpenAPI Specification

# OpenAPI 3.0 specification
openapi: 3.0.0
info:
  title: User Management API
  version: 1.0.0
  description: API for managing users

servers:
  - url: https://api.example.com/v1
    description: Production server

paths:
  /users:
    get:
      summary: List users
      operationId: listUsers
      tags:
        - Users
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  total:
                    type: integer
      security:
        - BearerAuth: []
    post:
      summary: Create user
      operationId: createUser
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserInput'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
          format: email
    
    CreateUserInput:
      type: object
      required:
        - name
        - email
      properties:
        name:
          type: string
        email:
          type: string
          format: email

Monitoring and Analytics

# CloudWatch metrics for API Gateway
resource "aws_api_gateway_stage" "prod" {
  rest_api_id   = aws_api_gateway_rest_api.main.id
  stage_name    = "prod"
  deployment_id = aws_api_gateway_deployment.main.id
  
  access_log_settings {
    destination_arn = aws_cloudwatch_log_group.api.arn
    format = "$context.requestId: $context.endpoint $context.httpMethod $context.status $context.responseLatency $context.requestTime"
  }
}

Key Metrics

Metric Description Alert Threshold
Latency Request processing time p95 > 2 seconds
ErrorRate Percentage of 5xx errors > 1%
RequestCount Total API requests Trend analysis
CacheHitRate Cache hit percentage < 60%
ThrottleRate Throttled requests > 0

Conclusion

API gateways are essential for managing API traffic securely and efficiently. Understanding gateway capabilities—authentication, rate limiting, routing, and monitoring—enables building robust API architectures.

Key considerations include implementing multiple security layers (API keys, OAuth, JWT), configuring appropriate rate limits based on backend capacity, using comprehensive monitoring for visibility, and maintaining clear API documentation for developer productivity.

As APIs become increasingly central to application architectures, investing in API management becomes essential. The patterns and practices outlined in this guide provide a foundation for effective API management.


Resources

Comments