AV
HomeAboutProjectBlog

© 2026 Ave syah Shina. All rights reserved.

  1. Home
  2. Blog
  3. 05 — Building RESTful APIs: Resources, CRUD, Naming, Versioning

05 — Building RESTful APIs: Resources, CRUD, Naming, Versioning

August 13, 20267 min read
Download as Markdown

"Use HTTP verbs correctly" was the extent of my REST knowledge, and it produced endpoints that technically obeyed the verbs and still felt arbitrary. The model that finally clicked: a REST API is a model of your domain expressed as resource nouns, manipulated by the four CRUD operations, named consistently enough that a consumer can predict endpoints they've never seen, and versioned so it can change without breaking anyone. [1] Once I saw it that way, "RESTful design" stopped being a checklist of HTTP trivia and became a small set of modeling decisions.

The thread connecting these nodes is that they're all consequences of one principle: the URL names a resource, the verb names the operation, and the contract should be predictable enough to guess. [2] Every naming and versioning rule I follow is in service of that predictability.

Resource modeling: design the nouns first

Before any endpoint, the work is deciding what the resources are [1]. A resource is a thing in your domain — an order, a user, a document, a comment. Good resource modeling is a modeling exercise, not an HTTP exercise: list the nouns in your domain, decide which are top-level (worth their own /orders collection) versus nested (an order's items live under /orders/{id}/items), and drop the ones that are really just fields on another resource.

The mistake I made early was modeling endpoints around UI screens ("a /dashboard endpoint") or around actions ("a /resetPassword endpoint"). Both leak the wrong abstraction. Resources are domain nouns; screens and actions get assembled from resource calls. If the only way to describe an endpoint is a verb, it's probably a sub-resource or an RPC-shaped exception — and those should be rare in a REST design.

CRUD: the four operations, mapped to verbs

Almost everything you do to a resource is one of Create, Read, Update, Delete [3]. REST maps these directly onto HTTP verbs, and the mapping is the spine of the whole style:

CRUD ↔ HTTP, on the /orders resource Create POST /orders → 201 Created Read GET /orders/42 → 200 OK Update PUT /orders/42 → 200 OK Delete DELETE /orders/42 → 204 No Content

A few conventions that fall out of this mapping [3]:

  • Create is POST to the collection (/orders); the server assigns the ID and returns 201 with a Location header pointing at the new resource.
  • Read is GET — to the collection for a list, or to /orders/{id} for one. These are two distinct operations.
  • Update is PUT (full replace) or PATCH (partial). The distinction matters: PUT to /orders/42 should replace the whole resource; PATCH changes only the fields sent.
  • Delete is DELETE to the specific resource, conventionally returning 204 No Content (nothing to return) rather than 200.

The discipline is treating this mapping as the default and reaching for exceptions deliberately. An endpoint that doesn't fit CRUD (e.g., "cancel an order," "send an invoice") is sometimes better modeled as a sub-resource action (POST /orders/42/cancel) than forced into the wrong verb. The point is to notice when you're leaving the CRUD spine and decide consciously.

URI design and naming conventions

Once resources exist, the URL shape follows rules that exist purely for predictability [2][4]:

  • Plural nouns for collections — /users, not /user. A single user is /users/42.
  • Lowercase, kebab-case in paths — /password-resets, not /passwordResets or /PasswordResets.
  • No verbs in paths — the verb is the HTTP method. /users/42 not /getUser/42.
  • Hierarchy expresses nesting — /users/42/orders means "orders belonging to user 42." Nest only when the parent is a true scope; avoid more than two levels.
  • Consistent field casing in JSON — pick camelCase or snake_case and apply it everywhere. Mixed casing in one API is the fastest way to erode trust.

The payoff of consistency: a consumer who has seen /users and /orders can correctly guess /comments without reading docs. That predictability is the usability of a REST API [4]. An inconsistent API forces the consumer to memorize every endpoint; a consistent one lets them infer.

Versioning: the contract can change

An API is a contract, and contracts that can't evolve die. Versioning is how you change the contract without breaking existing clients [5]. The roadmap highlights three strategies, each with tradeoffs:

  • URI versioning — /v1/orders, /v2/orders. Blunt, obvious, cache-friendly. The downside is ugly URLs and the temptation to bump versions too often. This is the most common choice in practice.
  • Header versioning — same URL, version in a custom header (Accept-version: v2). Cleaner URLs, but invisible in casual inspection and harder to test in a browser.
  • Media type versioning — version baked into the Accept header (Accept: application/vnd.example.v2+json). Most "RESTful" in theory, least ergonomic in practice.

The rule I hold: a breaking change requires a version bump; a non-breaking change (adding a field, adding an endpoint) does not. Most evolutions should be additive. When a real breaking change is unavoidable, ship the new version, give consumers a deprecation window measured in months not days, and document the migration path. The version is a promise that the old contract still works.

Simple JSON APIs

Underneath all of this, the wire format is almost always JSON [6]. A well-shaped REST response is a JSON object that consistently represents a resource — the same fields in the same casing every time, errors in a conventional shape, relationships either embedded or linked. The JSON:API spec formalizes this, and even if you don't adopt it wholesale, its conventions (a data envelope, a consistent errors array, sideloaded relationships) are good defaults to borrow. The discipline is treating the JSON shape as part of the contract — once clients depend on a field, renaming or removing it is a breaking change.

How I use this

When designing a new endpoint, I work noun-first. I name the resource, decide its CRUD surface, place it in the URL hierarchy where a consumer would expect to find it, and only then write the handler. When reviewing an existing API, the first thing I check is consistency — plural nouns, casing, status codes — because inconsistency is usually the loudest signal of an API that was assembled rather than designed. And when a change is needed, I ask the additive-or-breaking question first: additive changes ship immediately, breaking changes go through a version bump and a deprecation window. The contract is the part I'm promising; the noun-first shape is what makes that promise predictable.

References

[1] Integrate.io, "How to Make a RESTful API," 2024. [Online]. Available: https://www.integrate.io/blog/how-to-make-a-rest-api/

[2] CSS-Tricks, "Guidelines for URI Design," 2024. [Online]. Available: https://css-tricks.com/guidelines-for-uri-design/

[3] Palantir, "Rethinking CRUD For REST API Designs," 2023. [Online]. Available: https://blog.palantir.com/rethinking-crud-for-rest-api-designs-a2a8287dc2af

[4] restfulapi.net, "REST API URI Naming Conventions and Best Practices," 2024. [Online]. Available: https://restfulapi.net/resource-naming/

[5] Postman, "What is API Versioning?," 2024. [Online]. Available: https://www.postman.com/api-platform/api-versioning/

[6] JSON:API, "Specification for Building APIs in JSON," jsonapi.org, 2024. [Online]. Available: https://jsonapi.org/

Knowledge check · Question 1 of 5

You need to create a new order. The idiomatic REST call is…

Comments

Leave a Comment

You must be signed in to comment

0 Comments

No comments yet. Be the first to comment!