Hi Friends,
Welcome to the 193rd issue of the Polymathic Engineer. This week, we are concluding our series of articles on API design.
So far, we have examined the rules and best practices for designing REST APIs. Then we transformed the API layout into a machine-readable file so that the CI/CD pipeline could verify compliance. Throughout this process, we assumed that our APIs relied exclusively on REST and JSON.
That assumption holds true for the Booking API we designed for an external partner. But the booking service also interacts with the payment service, the notification service, and the event catalog, making thousands of calls per second. Why would you want to pay the same cost per call on your own infrastructure as you would across the internet?
That is the question we will address today. The right API format depends on where the traffic comes from, and most real systems end up adopting more than one.
The outline is:
What RPC really is
North-south vs east-west traffic
gRPC and Protocol Buffers
When performance tips the scale
Where GraphQL fits
Can one service offer both?
To learn technical skills, you must work on real projects. CodeCrafters is a great platform for that. You can build your own Redis, Kafka, DNS server, SQLite, HTTP server, or Git from scratch using your chosen programming language.
What RPC really is
REST can provide a domain model and abstract away the underlying technology for the consumer, but it’s not the only way for services to communicate. Remote Procedure Calls (RPC) rely on a different but simple concept: you invoke what looks like a regular function in one process, but it runs in another process—usually on a different machine.
On the client side, the stub makes this work. When the caller invokes getBooking(42), it really calls generated code that packs the arguments into a message, sends it over the network, waits for the reply, and unpacks the result. The network is transparent to the caller. We dedicated an entire issue to how remote procedure calls work under the hood, so we won’t repeat the technicalities here.
The most used RPC framework nowadays is gRPC, initially created by Google and released as open source in 2015. Since 2017, the project has been hosted by the CNCF and is the de facto standard on most platforms.
The fundamental difference compared to REST lies not in the syntax, but in state management. As we saw in the first article, REST is stateless by definition. With RPC, state depends on the specific implementation. Clients and servers can maintain state across calls, which can enhance performance but makes routing and recovery more difficult. If a server container fails, its replacement doesn’t know where you left off.
The trade-off is an exchange that couples producer and consumer more tightly than a resource model does. But let's be honest: coupling is not always the enemy. Between two services owned by the same team, deployed and monitored together, it might be a price you are happy to pay for speed.
North-south vs east-west traffic
Ultimately, the API format you use depends on where the request comes from. Engineers split API traffic into two groups and named them according to how architecture diagrams are drawn.
North-south traffic describes requests originating from outside the ecosystem. It’s the partner calling the Booking API, or a mobile app hitting your public endpoints. East-west traffic describes requests originating within the ecosystem and flowing entirely inside your cluster between your own microservices. For example, the booking service asks the payment service to charge a credit card.
These two kinds of traffic live in completely different worlds and have extremely different performance characteristics.
In a north–south exchange, traffic crosses the internet. The internet adds significant latency—DNS resolutions, TLS handshakes, the user's network—and clients can be written in any language using any HTTP library. It is natural to choose a low barrier-to-entry format such as REST over JSON.
East-west exchanges stay in your infrastructure. Round-trip times are measured in fractions of a millisecond, and you control both ends of every connection. Here the priorities flip: there is no need for a low barrier to entry between two services you manage directly, whereas every microsecond of overhead matters.
The real killer here is the compounding effects of each service. North-south requests rarely map to a single internal call. For a partner request, the booking service might check availability, calculate the price, and load the user profile. A single request fans out into 5-10 internal exchanges. You will pay several times over for every millisecond you squander on an internal hop before the response makes it back to the consumer.
This lens is also a classic discriminator in system design interviews. Weak candidates usually pick one format and apply it everywhere. Stronger ones ask where the traffic comes from before choosing, and give a different answer for the public API than for the internal calls behind it.
The decision rule is therefore natural: north-south traffic values low coupling and simplicity of adoption; east-west traffic values efficiency.
gRPC and Protocol Buffers
gRPC is better suited than REST for east–west services, thanks to smaller data payloads and faster communication within the ecosystem. gRPC is schema-first. Before writing any code, you describe the API in a .proto file, including the messages being exchanged and the methods that can be invoked. The contract for our booking service looks like this:
message Booking {
int32 id = 1;
string displayName = 2;
string event = 3;
}
service BookingService {
rpc GetBooking(BookingRequest) returns (Booking);
}


