Um momento
0x30Lesson 4 of 15

Synchronous APIs: REST and gRPC

Design request-response APIs between services, evolve them without breaking clients, and budget latency across call chains.

28 min 7-question quiz 2 code exercises
By the end of this lesson you can
  • Compare REST over HTTP/JSON with gRPC over HTTP/2 and Protocol Buffers
  • Evolve an API without breaking consumers: additive changes, versioning and deprecation
  • Estimate latency for serial and parallel call chains, and set timeouts

When the Ordering service needs a dish’s price right now, it asks the Menu service and waits. That’s synchronous communication: request, response. The two common styles:

RESTgRPC
TransportHTTP/1.1 or 2HTTP/2
PayloadJSON (human-readable)Protocol Buffers (compact binary)
ContractOpenAPI document, often optional.proto file, required, generates client and server code
Strengthsuniversal, easy to debug with curl, great for public APIsfast, strongly typed, streaming, great between internal services
REST: get a dish
1GET /menu/dishes/42 HTTP/1.1
2Host: menu.internal
3Accept: application/json
4
5HTTP/1.1 200 OK
6Content-Type: application/json
7
8{"id": 42, "name": "Spicy Miso Ramen", "price_cents": 1450, "spicy_level": 3}
menu.proto (gRPC)
1syntax = "proto3";
2
3service Menu {
4  rpc GetDish (GetDishRequest) returns (Dish);
5}
6
7message GetDishRequest {
8  int32 id = 1;
9}
10
11message Dish {
12  int32 id = 1;
13  string name = 2;
14  int32 price_cents = 3;
15  int32 spicy_level = 4;   // added later: old clients simply ignore it
16}

Evolving APIs without breaking anyone

Independent deployment only works if one service can change its API without forcing every caller to change at the same moment. The rules for a response that others read:

ChangeSafe?
Add a new optional field✅ old clients ignore it ( tolerant reader: clients must ignore unknown fields)
Remove a field❌ clients reading it break
Rename a field❌ it’s a remove plus an add
Change a field’s type ("1450" → 1450)❌
Make a required field optional (may now be missing)❌ for readers that rely on it

When you must break things, version: /v2/menu/dishes/42 (or a new gRPC service), run v1 and v2 side by side, tell consumers about the deprecation, and remove v1 only once its traffic is gone. In protobuf, never reuse a field number.

Latency adds up

Every synchronous hop adds latency, and a chain is only as available as all its links multiplied together: five services at 99.9% availability each give about 99.5%. When calls don’t depend on each other, run them in parallel - the total is then the slowest, not the sum. And always set a timeout: without one, a slow downstream service ties up your threads until you fall over too.

latency_budget.py
1menu, customer, stock, payment = 40, 60, 25, 120          # milliseconds
2
3serial = menu + customer + stock + payment
4parallel_then_pay = max(menu, customer, stock) + payment     # the three lookups don't depend on each other
5print(f"all serial: {serial} ms")
6print(f"lookups in parallel, then pay: {parallel_then_pay} ms")
7print(f"availability of 4 services at 99.9%: {0.999 ** 4:.4%}")
Output
all serial: 245 ms
lookups in parallel, then pay: 180 ms
availability of 4 services at 99.9%: 99.6006%

Key takeaways

  • REST (HTTP + JSON) is universal and easy to debug; gRPC (HTTP/2 + protobuf) is fast and strongly typed.

  • Additive changes are safe; removing, renaming or retyping fields breaks consumers - version and deprecate instead.

  • Latency and failure compound along synchronous chains; parallelize independent calls.

  • Every remote call needs a timeout.

Lesson quiz

7 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: simulate microservice patterns in Python

Build small Python simulations of the patterns - routers, sagas, outboxes, circuit breakers, traces - and run them against sample inputs. They run locally in your browser; no servers or containers needed.

Exercise 1

Is this change breaking?

+25 XP

The input has old: field lines, then new: field lines, for a response schema: name type required|optional. Compare them and print one line per difference, in old-field order and then new fields in order:

  • removed price: BREAKING
  • price_cents: type int -> string BREAKING
  • spicy_level: required -> optional BREAKING (readers relied on it)
  • notes: optional -> required ok
  • added allergens: ok

Then verdict: compatible or verdict: breaking (needs a new version).

  • Risky release
  • Safe release
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Exercise 2

Fit the latency budget

+25 XP

The first input line is the latency budget in milliseconds. Each following line is a stage of the request: serial name=ms (one call) or parallel name=ms name=ms ... (calls made at the same time). Stages run one after another. Print each stage’s cost (stage 1 (parallel): 60 ms, slowest customer), then total: 180 ms of 200 ms - ok or - OVER BUDGET by 25 ms. Finally print the slowest single call: slowest call: payment (120 ms).

  • Checkout
  • Too slow
main.py
Loading editor…

Python runs in a sandboxed browser worker with a 60 second time limit. Its runtime loads from the Pyodide CDN; your code stays in this browser.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Loading posts…

Gostou da aula? 😆👍
Apoie nosso trabalho com uma doação: