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!