"Most 'REST APIs' shipping today are RPC with HTTP costumes. That's not an insult — it's a useful observation. The question isn't 'which is correct' but 'which mental model are you actually using and is it serving you?'"
Two Design Centers
When you sit down to design an API, the first decision shapes everything that follows: what is the API organized around?
Resource-oriented (REST proper). The world is made of things — users, orders, payments, conversations. Each thing lives at a URI. The seven HTTP methods act on them. Reading is GET; creating is POST to a collection; replacing is PUT; deleting is DELETE. The verbs are pre-defined; you only design nouns.
RPC (Remote Procedure Call). The world is made of operations — createUser, processPayment, finalizeCouncil. Each operation has a procedure name and arguments. You POST a payload to invoke it. The nouns disappear into the procedure names; the verbs are unbounded (you invent new ones as needed).
Both work. Both ship in production. The decision is which mental model fits the domain and your team's habits.
The Litmus Test — Count Your URIs
Look at any API's URI list. If most URIs name things (/users/42, /orders/abc, /payments/xyz), it's resource-oriented. If most URIs name operations (/createUser, /processOrder, /getPaymentStatus), it's RPC.
A quick survey of 2026's well-known APIs:
- Resource-leaning: Stripe (mostly), GitHub REST, AWS S3, Kubernetes API. URIs name things.
- RPC-leaning: Slack Web API (
chat.postMessage,users.list), most gRPC services, OpenAI Chat Completions (POST /v1/chat/completions). URIs name operations. - Hybrid: Most real APIs. Resource URIs for the obvious nouns, plus action endpoints for operations that don't fit (
POST /payments/{id}/refund,POST /jobs/{id}/cancel). cwkPippa is in this bucket.
When Each Model Shines
Resource-oriented wins when:
- The domain has clear nouns. CRUD-heavy applications (admin panels, content management, e-commerce catalogs) map cleanly.
- Cache friendliness matters. GET-driven access is what CDNs were built for.
- Clients are diverse (browsers, mobile, third-party integrations). The seven verbs are universally understood; learning a new noun is easier than learning a new procedure.
- You want to expose discoverability and convention.
/users/{id}/ordersis self-explanatory;getOrdersForUser(userId)requires reading docs.
RPC-leaning wins when:
- The domain is operation-heavy. AI chat ("complete this prompt"), workflow orchestration, transcoding, ML inference — all naturally read as "do X with these args."
- You control both client and server tightly. gRPC/Protobuf is the canonical example: typed contracts, generated stubs, code-first.
- The operations don't naturally map to nouns. "Send a notification to these users on these channels with this severity" is awkward as a resource; clean as a procedure.
The Hybrid in Practice
Most production APIs land on resource-oriented with action sub-resources for awkward operations. The pattern: nouns at the top level (/orders, /payments), actions as sub-paths under a specific resource (POST /orders/42/cancel, POST /payments/xyz/refund). The action is named, the verb is POST (because actions are typically not idempotent without coordination), and the target is the parent resource.
Why this works: discovery is preserved (you find /orders/42 and see what you can do to it), the resource-oriented mental model stays intact, and the operations that genuinely don't fit ("refund" isn't a noun, it's a thing-you-do-to-a-payment) get a clean home.
cwkPippa's Mix
backend/routes/ is resource-oriented: /api/conversations, /api/folders, /api/messages, /api/artifacts all act like resources with GET/POST/PUT/PATCH/DELETE. But POST /api/council/{id}/finalize, POST /api/council/{id}/inject, POST /api/heartbeat/cron/{id}/run-now are action endpoints — they don't fit the resource model because they're operations on existing resources, not creates. The mix is deliberate; trying to force council finalization into a 'finalizations' resource would be ceremony for its own sake.