I’ve been thinking about how modern applications talk to each other. It’s not just one big program anymore. We have many small services, each doing a specific job. How do we manage all these conversations? How do we keep things secure, fast, and reliable when dozens of services need to connect? This question led me down a path of building gateways—the traffic directors of the software world.
Let’s talk about API gateways. Think of a gateway as a receptionist for a large office building. Instead of letting visitors wander around looking for the right department, the receptionist directs them. An API gateway does this for software. It sits between your users and your collection of backend services. It routes requests, checks credentials, and manages traffic flow.
Why would you need one? If you have more than a couple of services, things get messy fast. Each service might have a different address. You’d need security and logging in every single one. A gateway centralizes this. It provides one front door. All your rules about who can do what, and how often, live in one place.
I started with a simple custom gateway using Express.js. It’s a great way to understand the core concepts. You create a server that listens for requests. Then, based on the request path, you forward it to the correct backend service. Here’s a basic structure.
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
// Route requests for '/users' to the user service
app.use('/users', createProxyMiddleware({
target: 'http://localhost:3001',
changeOrigin: true,
}));
// Route requests for '/orders' to the order service
app.use('/orders', createProxyMiddleware({
target: 'http://localhost:3002',
changeOrigin: true,
}));
app.listen(3000, () => {
console.log('Gateway running on port 3000');
});
This works, but it’s static. The addresses are hardcoded. What happens when the user service moves or a new instance starts up? You’d have to stop your gateway and update the code. That’s not practical for a system that needs to be always available.
This is where service discovery comes in. Instead of hardcoding addresses, your gateway needs to ask a directory: “Where is the user service right now?” A tool like Consul acts as this dynamic phone book. Services register themselves when they start. The gateway queries Consul to find them.
Setting up Consul is straightforward. You run it as a separate process. Services send a heartbeat to say, “I’m alive.” The gateway can then get a list of all healthy instances. But how do you make this automatic? You need a client in your gateway that talks to Consul.
const Consul = require('consul');
class ServiceDiscovery {
constructor() {
this.consul = new Consul({ host: 'localhost', port: 8500 });
}
async findService(serviceName) {
try {
// Ask Consul for healthy instances of a service
const instances = await this.consul.health.service({
service: serviceName,
passing: true
});
// Pick one (simple round-robin logic)
if (instances.length > 0) {
const instance = instances[0];
return `http://${instance.Service.Address}:${instance.Service.Port}`;
}
throw new Error(`Service ${serviceName} not found`);
} catch (error) {
console.error('Discovery failed:', error);
throw error;
}
}
}
Now, your gateway can use this findService method to get a live address before forwarding a request. But what if the service you pick is slow or failing? You don’t want to send all traffic to a broken instance. This is where patterns like circuit breakers and retries become critical.
A circuit breaker is like a fuse in your house. If a service fails too many times, the “circuit” trips. The gateway stops sending requests to it for a while, giving it time to recover. This prevents a cascade of failures. After a timeout, it tries again to see if the service is back.
Have you considered what happens during a sudden traffic spike? Your gateway needs to protect your services from being overwhelmed. This is where rate limiting shines. You can define rules like “a single IP can only make 100 requests per minute to the login endpoint.” It’s a simple but powerful defense.
While building a custom gateway teaches you a lot, maintaining it for production is a big job. You need to handle updates, scaling, and complex security policies. This is why many teams use a dedicated gateway like Kong. Kong is built for this. It runs as a separate layer, often in its own containers. You configure it with declarative files instead of writing lots of code.
A Kong configuration might define a route and attach plugins to it. A plugin could be for rate-limiting, authentication, or logging. The power is in this plugin system. You get battle-tested features without building them yourself. Here’s a glimpse of what a Kong config looks like in YAML.
_format_version: "2.1"
services:
- name: user-service
url: http://user-service.default.svc.cluster.local
routes:
- name: user-route
paths:
- /users
plugins:
- name: rate-limiting
config:
minute: 20
policy: local
You define a service and its upstream address. You define a route that matches certain paths. Then you attach plugins to that route. Kong handles the rest. It integrates with Consul too, so it can also do dynamic service discovery.
So, when do you use a custom Express gateway versus Kong? Start with Express if you have simple needs or want full control over the logic. It’s also excellent for learning. Choose Kong when you need enterprise features, high performance under load, and a team to manage the infrastructure. Kong takes the operational burden off your application code.
Monitoring is non-negotiable. You must know how your gateway is performing. How many requests are failing? What’s the average response time? Tools like Prometheus collect metrics. You can expose a /metrics endpoint from your gateway. Then, a dashboard tool like Grafana can visualize the data. This lets you spot problems before users do.
Let’s not forget security. The gateway is your first line of defense. It should validate API keys or JSON Web Tokens (JWT) before a request even reaches your business logic. It should also strip out any sensitive headers from the response that might leak internal information. Centralizing this logic is much safer than hoping every service team implements it correctly.
Building a robust gateway system connects several pieces: the routing logic, the service directory, the safety features like circuit breakers, and the observability tools. It might seem complex, but each piece solves a clear problem. Start simple. Get a basic proxy working. Add service discovery. Then introduce resilience patterns. Finally, consider moving to a dedicated tool like Kong as your needs grow.
What’s the biggest challenge you’ve faced when connecting multiple services? Was it finding them, securing them, or keeping them fast? I find that starting with a clear map of all service interactions helps. Draw it out. Identify the critical paths. Then build your gateway strategy around those.
I hope this walk through API gateways gives you a foundation to build upon. The goal is to make your network of services feel like a single, coherent application to your clients. It’s a challenging but rewarding piece of modern architecture. If this exploration helped you, please share it with a colleague who might be facing similar design decisions. I’d also love to hear your thoughts or questions in the comments below—what’s your experience with managing microservice communication?
As a best-selling author, I invite you to explore my books on Amazon. Don’t forget to follow me on Medium and show your support. Thank you! Your support means the world!
101 Books
101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.
Check out our book Golang Clean Code available on Amazon.
Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!
📘 Checkout my latest ebook for free on my channel!
Be sure to like, share, comment, and subscribe to the channel!
Our Creations
Be sure to check out our creations:
Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | JS Schools
We are on Medium
Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva