MidПрактика3 min

API Gateway

API Gateway на AWS, Azure API Management и GCP API Gateway: REST-эндпоинты, CORS и маршрутизация

Зачем нужен API Gateway

API Gateway -- это "входная дверь" для вашего API. Он принимает HTTP-запросы от клиентов, маршрутизирует их к serverless-функциям и возвращает ответы. Без API Gateway вам пришлось бы самостоятельно реализовывать маршрутизацию, аутентификацию, rate limiting и CORS.

Функции API Gateway

Функция Описание
Маршрутизация Направляет GET /count к нужной Lambda
CORS Обрабатывает Cross-Origin запросы
Throttling Ограничивает количество запросов
Аутентификация API keys, JWT, OAuth
Трансформация Преобразование запросов/ответов
Кэширование Кэширование ответов для снижения нагрузки
Мониторинг Логирование, метрики, трейсинг

AWS API Gateway

AWS предлагает два типа API Gateway:

Тип Стоимость Для CRC
REST API $3.50/M запросов Больше возможностей
HTTP API $1.00/M запросов Рекомендуется для CRC

HTTP API дешевле на 70% и достаточен для CRC.

Создание HTTP API

# Создание HTTP API
aws apigatewayv2 create-api \
  --name crc-api \
  --protocol-type HTTP \
  --cors-configuration '{
    "AllowOrigins": ["https://resume.ivanpetrov.com"],
    "AllowMethods": ["GET", "OPTIONS"],
    "AllowHeaders": ["Content-Type"],
    "MaxAge": 86400
  }'

# Создание интеграции с Lambda
aws apigatewayv2 create-integration \
  --api-id API_ID \
  --integration-type AWS_PROXY \
  --integration-uri arn:aws:lambda:us-east-1:123456789012:function:visitor-counter \
  --payload-format-version "2.0"

# Создание маршрута
aws apigatewayv2 create-route \
  --api-id API_ID \
  --route-key "GET /count" \
  --target "integrations/INTEGRATION_ID"

# Создание стадии (auto-deploy)
aws apigatewayv2 create-stage \
  --api-id API_ID \
  --stage-name prod \
  --auto-deploy

Разрешение Lambda Invoke

# Даём API Gateway право вызывать Lambda
aws lambda add-permission \
  --function-name visitor-counter \
  --statement-id apigateway-invoke \
  --action lambda:InvokeFunction \
  --principal apigateway.amazonaws.com \
  --source-arn "arn:aws:execute-api:us-east-1:123456789012:API_ID/*/GET/count"

Результат

URL: https://API_ID.execute-api.us-east-1.amazonaws.com/prod/count

Альтернатива: Lambda Function URL

Для простых случаев (как CRC) можно использовать Lambda Function URL вместо API Gateway:

# Создаём Function URL (бесплатно!)
aws lambda create-function-url-config \
  --function-name visitor-counter \
  --auth-type NONE \
  --cors '{
    "AllowOrigins": ["https://resume.ivanpetrov.com"],
    "AllowMethods": ["GET"],
    "AllowHeaders": ["Content-Type"]
  }'

Lambda Function URL -- это бесплатно (входит в стоимость Lambda). Для CRC это отличная альтернатива.

Azure API Management

Azure Functions уже имеет HTTP endpoint

В Azure Functions HTTP trigger создаёт endpoint автоматически:

https://crc-visitor-counter.azurewebsites.net/api/count

Для CRC этого достаточно. API Management нужен для более сложных сценариев.

Когда нужен Azure API Management

# Создание API Management (Consumption tier -- serverless)
az apim create \
  --name crc-apim \
  --resource-group crc-resources \
  --publisher-name "CRC" \
  --publisher-email "[email protected]" \
  --sku-name Consumption

# Импорт Function App как API
az apim api import \
  --resource-group crc-resources \
  --service-name crc-apim \
  --path /api \
  --specification-format OpenApi \
  --specification-url "https://crc-visitor-counter.azurewebsites.net/api/swagger.json"

CORS в Azure Functions

// host.json
{
  "extensions": {
    "http": {
      "routePrefix": "api"
    }
  },
  "cors": {
    "allowedOrigins": [
      "https://resume.ivanpetrov.com"
    ],
    "supportCredentials": false
  }
}

GCP API Gateway

Cloud Functions уже имеет HTTP endpoint

Как и Azure, GCP Cloud Functions с HTTP trigger создаёт endpoint:

https://us-central1-PROJECT_ID.cloudfunctions.net/visitor-counter

Когда нужен GCP API Gateway

# Создание API config
cat > api-config.yaml << 'EOF'
swagger: '2.0'
info:
  title: CRC API
  version: '1.0'
host: crc-api-HASH.apigateway.PROJECT_ID.cloud.goog
schemes:
  - https
paths:
  /count:
    get:
      operationId: getCount
      x-google-backend:
        address: https://us-central1-PROJECT_ID.cloudfunctions.net/visitor-counter
      responses:
        '200':
          description: Success
EOF

# Создание API
gcloud api-gateway apis create crc-api

# Создание конфигурации
gcloud api-gateway api-configs create crc-config \
  --api=crc-api \
  --openapi-spec=api-config.yaml

# Создание gateway
gcloud api-gateway gateways create crc-gateway \
  --api=crc-api \
  --api-config=crc-config \
  --location=us-central1

CORS: Cross-Origin Resource Sharing

Проблема

Ваш фронтенд на resume.ivanpetrov.com делает fetch-запрос к API на api.ivanpetrov.com. Это кросс-доменный запрос, и браузер блокирует его по умолчанию из соображений безопасности.

Решение: CORS-заголовки

Access-Control-Allow-Origin: https://resume.ivanpetrov.com
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400

Где настраивать CORS

Провайдер Где настраивать
AWS HTTP API В конфигурации API Gateway
AWS Lambda URL В конфигурации Function URL
Azure Functions В host.json или Application Settings
GCP Cloud Functions В коде функции (response headers)

Частая ошибка: Access-Control-Allow-Origin: *

# ПЛОХО для production (но OK для разработки):
'Access-Control-Allow-Origin': '*'

# ХОРОШО для production:
'Access-Control-Allow-Origin': 'https://resume.ivanpetrov.com'

* разрешает запросы с любого домена. Для CRC это не критично, но для production-систем используйте конкретный домен.

Тестирование API

curl

# Простой GET-запрос
curl https://API_ID.execute-api.us-east-1.amazonaws.com/prod/count

# С заголовками (проверка CORS)
curl -v -H "Origin: https://resume.ivanpetrov.com" \
  https://API_ID.execute-api.us-east-1.amazonaws.com/prod/count

# OPTIONS preflight
curl -X OPTIONS \
  -H "Origin: https://resume.ivanpetrov.com" \
  -H "Access-Control-Request-Method: GET" \
  https://API_ID.execute-api.us-east-1.amazonaws.com/prod/count

Ожидаемый ответ

{
  "count": 42
}

С заголовками:

HTTP/2 200
content-type: application/json
access-control-allow-origin: https://resume.ivanpetrov.com
access-control-allow-methods: GET, OPTIONS

Сравнение подходов

Параметр AWS HTTP API Azure Functions GCP Cloud Functions
Отдельный API GW Да Нет (встроено) Нет (встроено)
CORS В API Gateway В host.json В коде
Custom domain Через API Gateway Через Function App Через API Gateway
Rate limiting Встроено Через APIM Через API Gateway
Стоимость $1/M запросов Бесплатно Бесплатно
Free Tier 1M запросов/мес Неограниченно Неограниченно

Проверь себя

Почему Access-Control-Allow-Origin: '*' нежелателен для production?

Что такое CORS и почему он нужен в CRC?

В каком провайдере HTTP-эндпоинт для serverless-функции создаётся автоматически без отдельного API Gateway?

Что такое Lambda Function URL и почему она может заменить API Gateway для CRC?

Почему для CRC рекомендуется AWS HTTP API, а не REST API?