# REST, gRPC and GraphQL

> Three API styles and where each one fits: public APIs, service-to-service, and client-shaped reads.

Concept · Networking & APIs · https://levelcode.org/concepts/rest-vs-grpc

Three styles dominate API design. They differ in how operations are described, how data is encoded, and who decides the shape of a response.

| | REST (JSON over HTTP) | gRPC | GraphQL |
|---|---|---|---|
| Model | Resources and HTTP methods | Remote procedure calls defined in `.proto` files | One endpoint; clients send queries for the fields they want |
| Encoding | JSON (text) | Protocol Buffers (binary) | JSON |
| Contract | OpenAPI (optional) | Required schema, generated client and server code | Required schema |
| Transport | HTTP/1.1 or HTTP/2 | HTTP/2 | HTTP |
| Streaming | Limited (SSE, chunked) | Client, server and bidirectional streams | Subscriptions (usually over WebSockets) |
| Caching | HTTP caches and CDNs work naturally for GETs | Not HTTP-cacheable | Hard to cache at HTTP level (often POST) |
| Browser support | Native | Needs gRPC-Web and a proxy | Native |

## Where each fits

- **REST** for public and partner APIs: universally understood, debuggable with `curl`, cacheable, and easy to version. The default when in doubt.
- **gRPC** for service-to-service calls inside your system: compact binary messages, strict contracts with generated clients, deadlines propagated across calls, and streaming. Its tooling assumes you control both ends.
- **GraphQL** when many different clients (web, iOS, Android) need differently shaped data from many backends. Clients fetch exactly the fields they need in one round trip, avoiding over-fetching and many sequential calls. The costs: query complexity limits are needed to stop expensive queries, caching moves into the client and server layers, and authorisation must be enforced per field.

## Design concerns that apply to all three

- **Idempotency:** retried mutations need [idempotency keys](https://levelcode.org/concepts/idempotency-keys).
- **Pagination:** use cursors, not offsets, for large lists ([keyset pagination](https://levelcode.org/concepts/keyset-pagination)).
- **Evolution:** add fields freely; never change the meaning of an existing one. Protobuf field numbers and GraphQL deprecations make this explicit.
- **Errors:** return a consistent, machine-readable error shape.

The Backend with Go roadmap's REST API design lesson goes deeper on resource modelling and error formats.
