API Gateway: the single entry point
An API Gateway centralizes cross-cutting concerns for all APIs: authentication, rate limiting, logging, request transformation, and routing. It eliminates the need to implement these functions in every individual microservice.
- Kong (open-source): the most flexible self-hosted option. Plugins for JWT auth, OAuth2, rate limiting, CORS, and request transformation. Deployable on Kubernetes with Kong's ingress controller.
- AWS API Gateway: native integration with Lambda, Cognito, and IAM. Ideal when the backend is primarily serverless or heavily AWS-dependent.
- Traefik: if already using Traefik as Kubernetes ingress controller, its middlewares cover most cases: basic/JWT auth, rate limiting, circuit breaking.
OAuth2 and JWT: correct authentication for enterprise APIs
The most common API authentication mistake: using static API keys without expiration or rotation. For enterprise APIs integrating internal systems and third parties, OAuth2 with short-lived JWT tokens is the correct standard.
// JWT validation with enterprise claim verification
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';
const client = jwksClient({
jwksUri: 'https://auth.company.com/.well-known/jwks.json',
cache: true,
cacheMaxAge: 86400000, // 24h cache for public keys
});
async function validateToken(token: string): Promise<JwtPayload> {
const decoded = jwt.decode(token, { complete: true });
if (!decoded?.header?.kid) throw new Error('Invalid token: missing kid');
const key = await client.getSigningKey(decoded.header.kid);
return jwt.verify(token, key.getPublicKey(), {
algorithms: ['RS256'],
audience: 'api.company.com',
issuer: 'https://auth.company.com',
}) as JwtPayload;
}Circuit Breaker: isolating third-party failures
When an external service (payment provider, geolocation API, ERP) starts failing or responding slowly, without a circuit breaker that behavior propagates to your system: your API waits for the third party's response while accumulating open connections until the thread pool is exhausted and your service also goes down.
import CircuitBreaker from 'opossum';
const breaker = new CircuitBreaker(callPaymentProvider, {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000,
volumeThreshold: 5,
});
breaker.fallback(() => ({
status: 'pending',
message: 'Payment provider unavailable, retrying automatically'
}));
breaker.on('open', () =>
logger.warn('Circuit breaker open: payment provider degraded')
);Retry with Exponential Backoff and Jitter
async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxAttempts = 4,
baseDelay = 1000
): Promise<T> {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxAttempts) throw error;
// Don't retry 4xx errors (client errors, not transient)
if (error instanceof ApiError && error.status >= 400 && error.status < 500) throw error;
const delay = Math.min(
baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000,
30000
);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
throw new Error('Unreachable');
}Reliable webhooks: idempotency and signature verification
app.post('/webhooks/payment', async (req, res) => {
// 1. Verify HMAC signature from provider
const sig = req.headers['x-webhook-signature'] as string;
const expected = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
.update(JSON.stringify(req.body)).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)))
return res.status(401).json({ error: 'Invalid signature' });
// 2. Idempotency: skip if already processed
const existing = await db.processedEvents.findUnique({
where: { event_id: req.body.event_id }
});
if (existing) return res.status(200).json({ status: 'already_processed' });
await processPaymentEvent(req.body);
await db.processedEvents.create({ data: { event_id: req.body.event_id, processed_at: new Date() } });
res.status(200).json({ status: 'ok' });
});Frequently Asked Questions
REST, GraphQL, or gRPC for internal enterprise APIs?
How do I manage API versions without breaking existing integrations?
How do I detect when a third-party integration is silently failing?
How do I document internal APIs in a way that doesn't go stale?
What is an API contract test and when is it necessary?
Does your company have fragile integrations causing frequent incidents? We can redesign integrations with the correct resilience patterns.
Talk to our team