// Communication & Integration · 01
REST / HTTP
Ask, then wait. Simple, universal, and blocked until it answers.
How it fits together
- Service A uses / calls Service B (1 GET /orders/42)
- Service B uses / calls Service A (2 200 + JSON)
- Service A fails / error path Timeout (no reply in 2s)
Spot it
- The caller needs an answer before moving on
- Third parties must integrate with plain tools
- Chained sync calls make p99 latency balloon
It costs
The caller is coupled in time: if the callee is slow or down, so is the caller.
In code
public sealed record Order(Guid Id, string Customer, decimal Total, int Version);app.MapPost("/orders", async (CreateOrder body, OrderDb db) =>{ var order = await db.AddAsync(body); return Results.Created($"/orders/{order.Id}", order);});app.MapGet("/orders/{id:guid}", async (Guid id, OrderDb db, HttpContext http) =>{ var order = await db.FindAsync(id); if (order is null) return Results.NotFound(); http.Response.Headers["ETag"] = $"\"{order.Version}\""; return Results.Ok(order);});app.MapPut("/orders/{id:guid}", async (Guid id, UpdateOrder body, OrderDb db, HttpContext http) =>{ var order = await db.FindAsync(id); if (order is null) return Results.NotFound(); if (http.Request.Headers["If-Match"].ToString() != $"\"{order.Version}\"") return Results.StatusCode(StatusCodes.Status412PreconditionFailed); var updated = await db.ReplaceIfVersionAsync(id, body, order.Version); if (updated is null) return Results.StatusCode(StatusCodes.Status412PreconditionFailed); http.Response.Headers["ETag"] = $"\"{updated.Version}\""; return Results.Ok(updated);});Go deeperThe full explanation and what to ask for · 1 min readExpandCollapse
REST models the system as resources addressed by URLs and changed through a small set of HTTP verbs. Its strength is reach: every language, proxy, cache and browser understands it, and GET responses can be cached by HTTP infrastructure itself.
The classic mistake is a chain of synchronous calls: A calls B calls C, so availability multiplies down and latency adds up. Another is ignoring method semantics: a retried POST can create the thing twice, while PUT and DELETE are defined as idempotent.
Use it when the caller needs an answer now, and put a timeout on every call. When the result can wait, a message queue or an event decouples the two in time; for chatty internal calls, gRPC is leaner.
Ask for it
- resource and verb
- status codes
- idempotent methods
- ETag / If-Match
- Problem Details
- cursor pagination
Expose orders as an HTTP API: GET /orders/{id} returns 200 or 404, POST /orders returns 201 with a Location header, errors use Problem Details, GET sends an ETag and PUT requires If-Match (412 on mismatch), GET /orders uses cursor pagination, and publish an OpenAPI document.