Skip to main content

API Gateway Template

Build production-ready API endpoints with authentication, rate limiting, request validation, response transformation, and monitoring. Turn workflows into secure, scalable APIs.

Time to build: 30 minutes Difficulty: Advanced Perfect for: Public APIs, third-party integrations, webhook endpoints, microservices


What It Does

Request → Authenticate → Rate limit → Validate → Process → Transform → Respond

Production-ready API layer with security, reliability, and monitoring built-in.


Step-by-Step

1. Create Workflow

  • New workflow → Name it "API Gateway - User Management"
  • Webhook trigger with custom URL: /api/v1/users

2. Extract API Key from Headers

  • Drag Function Block
  • Connect Webhook to Function
// Extract and validate API key
const authHeader = input.webhook.headers.authorization || "";
const apiKey = authHeader.replace("Bearer ", "");

if (!apiKey) {
throw new Error("Missing API key");
}

return {
api_key: apiKey,
method: input.webhook.method,
path: input.webhook.path,
body: input.webhook.body,
query: input.webhook.query,
ip: input.webhook.headers.x_forwarded_for || input.webhook.ip
};

3. Authenticate API Key

  • Drag Database Query Block
  • Connect Function to Database
SELECT
id,
user_id,
name,
rate_limit,
allowed_endpoints,
is_active,
expires_at
FROM api_keys
WHERE key_hash = encode(digest('<function.api_key>', 'sha256'), 'hex')
AND is_active = true
AND (expires_at IS NULL OR expires_at > NOW())

4. Validate Authentication

  • Drag Condition Block
Condition: <database.rows_found> > 0

If True: API key is valid
If False: Return 401 Unauthorized

5. Return Auth Error (False Path)

  • Drag Response Block on False path
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired API key",
"status": 401
},
"request_id": "<webhook.request_id>"
}

HTTP Status: 401
Headers:
Content-Type: application/json
X-Request-ID: <webhook.request_id>

6. Check Rate Limit (True Path)

  • Drag Database Query Block on True path
-- Check requests in last minute
SELECT COUNT(*) as request_count
FROM api_requests
WHERE api_key_id = <database.id>
AND created_at > NOW() - INTERVAL '1 minute'

7. Validate Rate Limit

  • Drag Condition Block
Condition: <database.request_count> < <database_auth.rate_limit>

If True: Within rate limit
If False: Return 429 Too Many Requests

8. Return Rate Limit Error (False Path)

  • Drag Response Block
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Try again later.",
"status": 429,
"retry_after": 60
},
"request_id": "<webhook.request_id>",
"rate_limit": {
"limit": <database_auth.rate_limit>,
"remaining": 0,
"reset": <rate_limit_reset_time>
}
}

HTTP Status: 429
Headers:
Content-Type: application/json
X-RateLimit-Limit: <database_auth.rate_limit>
X-RateLimit-Remaining: 0
X-RateLimit-Reset: <rate_limit_reset_time>
Retry-After: 60

9. Log API Request (True Path)

  • Drag Database Query Block
INSERT INTO api_requests (
api_key_id,
endpoint,
method,
ip_address,
user_agent,
request_body,
created_at
) VALUES (
<database_auth.id>,
'<function.path>',
'<function.method>',
'<function.ip>',
'<webhook.headers.user_agent>',
'<function.body>'::jsonb,
NOW()
) RETURNING id

10. Validate Request Body

  • Drag Agent Block for validation
Model: GPT-4o-mini

System Prompt:
"Validate this API request against the schema. Return 'valid' or list of validation errors.

Schema for POST /api/v1/users:
{
email: required, valid email format
name: required, 2-100 characters
role: optional, one of [user, admin]
}

Return JSON: { valid: boolean, errors: [] }"

User Prompt:
"Method: <function.method>
Body: <function.body>"

11. Check Validation Result

  • Drag Condition Block
Condition: <agent.valid> == true

If True: Request is valid
If False: Return 400 Bad Request

12. Return Validation Error (False Path)

  • Drag Response Block
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request data",
"status": 400,
"details": <agent.errors>
},
"request_id": "<webhook.request_id>"
}

HTTP Status: 400

13. Route to Handler (True Path)

  • Drag Condition Block for method routing
Condition: <function.method> == "GET"
True: Get user(s)

Condition: <function.method> == "POST"
True: Create user

Condition: <function.method> == "PUT"
True: Update user

Condition: <function.method> == "DELETE"
True: Delete user

14. GET Handler

  • Drag Database Query Block on GET path
SELECT
id,
email,
name,
role,
created_at,
updated_at
FROM users
WHERE
(<function.query.id> IS NULL OR id = <function.query.id>)
AND (<function.query.role> IS NULL OR role = <function.query.role>)
LIMIT COALESCE(<function.query.limit>, 100)
OFFSET COALESCE(<function.query.offset>, 0)

15. POST Handler

  • Drag Database Query Block on POST path
INSERT INTO users (
email,
name,
role,
created_by_api_key,
created_at
) VALUES (
'<function.body.email>',
'<function.body.name>',
COALESCE('<function.body.role>', 'user'),
<database_auth.id>,
NOW()
) RETURNING id, email, name, role, created_at

16. Transform Response

  • Drag Function Block to format response
// Transform database response to API format
return {
data: input.database.rows,
meta: {
count: input.database.rows.length,
request_id: input.webhook.request_id,
timestamp: new Date().toISOString()
},
links: {
self: `https://api.yourapp.com${input.function.path}`
}
};

17. Send Success Response

  • Drag Response Block
<function.output>

HTTP Status: 200 (GET) or 201 (POST)
Headers:
Content-Type: application/json
X-Request-ID: <webhook.request_id>
X-RateLimit-Limit: <database_auth.rate_limit>
X-RateLimit-Remaining: <rate_limit_remaining>
X-RateLimit-Reset: <rate_limit_reset_time>

18. Log Response

  • Drag Database Query Block
UPDATE api_requests
SET
response_status = <response.status>,
response_body = '<function.output>'::jsonb,
processing_time_ms = <workflow.duration_ms>,
completed_at = NOW()
WHERE id = <database_log.id>

19. Handle Errors Globally

  • Add error handler workflow
On any error:
1. Log error to database
2. Send alert if 5xx error
3. Return formatted error response
4. Update metrics

API Security Best Practices

Authentication Methods

API Keys (Implemented Above)

Pros: Simple, stateless
Cons: Less secure than OAuth
Use for: Internal APIs, trusted clients

OAuth 2.0

Pros: Industry standard, secure
Cons: More complex
Use for: Public APIs, third-party access

JWT Tokens

Pros: Stateless, scalable
Cons: Cannot revoke easily
Use for: Microservices, mobile apps

Rate Limiting Strategies

Fixed Window

100 requests per minute
Resets at :00 seconds
Simple but allows bursts

Sliding Window

100 requests per rolling 60 seconds
More accurate
Prevents burst abuse

Token Bucket

Bucket refills at steady rate
Allows bursts up to limit
Flexible and fair

Real-World Examples

Payment API Gateway

  • Stripe-like API
  • Idempotency keys
  • Webhook delivery
  • Retry logic

SaaS Product API

  • Multi-tenant isolation
  • Usage-based billing
  • API analytics
  • Developer dashboard

Internal Microservices Gateway

  • Service discovery
  • Load balancing
  • Circuit breaking
  • Distributed tracing

Public Data API

  • Free tier: 1,000 req/day
  • Pro tier: 100,000 req/day
  • Enterprise: Unlimited
  • Usage analytics

Advanced Features

Request/Response Transformation

// Transform external API format to internal format
// Transform internal response to external API format
// API versioning support

Caching

Cache GET requests for 5 minutes
Reduce database load
Faster response times
Cache invalidation on updates

API Versioning

/api/v1/users - Stable, deprecated
/api/v2/users - Current version
/api/v3/users - Beta features
Header-based versioning: Accept: application/vnd.api+json;version=2

Request Deduplication

Use Idempotency-Key header
Prevent duplicate requests
Store request signatures
Return cached response if duplicate

Webhooks

Deliver events to subscribers
Retry failed deliveries
Signature verification
Webhook logs and status

Monitoring and Analytics

Track Key Metrics

-- Most used endpoints
SELECT endpoint, COUNT(*)
FROM api_requests
WHERE created_at > NOW() - INTERVAL '24 hours'
GROUP BY endpoint
ORDER BY COUNT(*) DESC;

-- Average response time
SELECT endpoint, AVG(processing_time_ms)
FROM api_requests
GROUP BY endpoint;

-- Error rate
SELECT
DATE_TRUNC('hour', created_at) as hour,
COUNT(*) FILTER (WHERE response_status >= 500) * 100.0 / COUNT(*) as error_rate
FROM api_requests
GROUP BY hour;

Alerting

  • Error rate > 5%: Alert team
  • Response time > 1s: Investigate
  • Rate limit hit rate > 10%: Review limits

Developer Experience

API Documentation

  • Auto-generate OpenAPI spec
  • Interactive API explorer
  • Code examples in multiple languages
  • Webhook testing tools

SDK Generation

  • Generate client libraries
  • Python, JavaScript, Ruby, Go
  • Type-safe interfaces
  • Automatic retries

Developer Portal

  • API key management
  • Usage dashboards
  • Billing and invoicing
  • Support tickets

Enhancements

Add GraphQL Support

  • Single endpoint for all queries
  • Client-specified fields
  • Reduces over-fetching

Add WebSocket Support

  • Real-time updates
  • Bidirectional communication
  • Live notifications

Add API Mocking

  • Mock endpoints for testing
  • Sandbox environment
  • Faster client development

Add API Analytics

  • Track usage by customer
  • Popular endpoints
  • Error patterns
  • Performance trends

Cost

Infrastructure (per 1M requests):

  • Database queries: ~$0.50-1.00
  • AI validation: ~$0.20-0.50
  • Logging: ~$0.10-0.20
  • Total: ~$0.80-1.70

Per-request breakdown:

  • Auth check: ~$0.0001
  • Rate limit: ~$0.0001
  • Processing: ~$0.0005
  • Logging: ~$0.0001
  • Total: ~$0.0008 per request

Monthly cost (1M requests/month):

  • Infrastructure: ~$0.80-1.70
  • Monitoring: ~$5-10
  • Total: ~$5.80-11.70
Next Step

Combine with Error Handling for production-grade API reliability with retries and fallbacks!