Skip to main content

Command Palette

Search for a command to run...

REST API Design Made Simple with Express.js

Let's build that understanding from scratch, then apply it with Express.js.

Published
β€’6 min read
REST API Design Made Simple with Express.js
S

Frontend Developer πŸ’» | Fueled by curiosity and Tea β˜• | Always learning and exploring new technologies.

What Is an API?

API stands for Application Programming Interface. Ignore the formal definition for a moment and think about what's actually happening.

You have a client a browser, a mobile app, a CLI tool, another server and you have a server that knows things or can do things the client needs. The API is the agreed upon language they use to talk.

When a user logs into an app, the frontend doesn't just magically know their data.

It sends a request to the server:
"Hey, here's a username and password β€” does this check out? If so, give me this user's profile."

The server checks, and responds:
"Yes, here it is."

That exchange, the format of the request, the format of the response is the API.

REST is a specific way of designing that exchange. It uses HTTP (the same protocol your browser uses to load web pages) and a set of conventions that make APIs predictable and consistent.

The Core Idea

REST stands for Representational State Transfer. The jargon doesn't help much. What does help is understanding the concept of a resource.

In REST, everything you expose through your API is a resource β€” a noun, a thing. Users are a resource. Posts are a resource. Orders, products, comments β€” all resources.

Each resource has a URL that identifies it. That URL is called an endpoint. The naming convention is clean: always use plural nouns, always lowercase, no verbs.

Good:
  /users
  /users/42
  /posts
  /posts/7/comments

Bad:
  /getUsers
  /deleteUser?id=42
  /createNewPost

The bad examples describe actions, not resources. The action is communicated via the HTTP method, not the URL. The URL should only tell you what you're operating on the HTTP method tells you how.

HTTP Methods: The Verbs of REST

HTTP ships with a set of methods sometimes called verbs that describe the intended operation on a resource. REST maps these directly to the four classic database operations known as CRUD: Create, Read, Update, Delete.

GET β€” Retrieve a resource. Read-only. Should never modify anything. Safe to call multiple times.

POST β€” Create a new resource. Sends data in the request body. Used when the server generates the ID.

PUT β€” Replace an existing resource entirely. You send the full updated version, the server stores it as-is.

DELETE β€” Remove a resource.

There's also PATCH, which is worth knowing even though it's less universal: it partially updates a resource. Where PUT replaces everything, PATCH just changes the fields you send. For a user profile, PUT would require sending name + email + age + every other field even if you're only changing the email. PATCH lets you send just { "email": "new@email.com" }.

Status Codes: The Server's Reply

When your server responds, it includes a status code a three-digit number that tells the client whether things went well, and if not, why not. Most developers know 404. There are many more.

The codes are grouped by their first digit:

2xx β€” Success

  • 200 OK β€” generic success. Used for successful GET, PUT, PATCH responses.

  • 201 Created β€” resource was successfully created (POST responses).

  • 204 No Content β€” success, but nothing to return (DELETE responses).

4xx β€” Client errors (the request was wrong)

  • 400 Bad Request β€” the client sent malformed data.

  • 401 Unauthorized β€” no authentication was provided.

  • 403 Forbidden β€” authenticated but not allowed.

  • 404 Not Found β€” the resource doesn't exist.

  • 409 Conflict β€” the request conflicts with current state (e.g. duplicate email).

  • 422 Unprocessable Entity β€” data was well-formed but failed validation.

5xx β€” Server errors (something broke on your end)

  • 500 Internal Server Error β€” generic catch-all server failure.

  • 503 Service Unavailable β€” server is down or overloaded.

401 vs 403 is a distinction almost every junior API makes incorrectly. 401 means "who are you? I don't know you." 403 means "I know who you are, but you can't do this." If a user is logged in and tries to access another user's private data, that's a 403, not a 401. If there's no token at all, it's a 401.

Also: 404 vs 403 for private resources is a deliberate security decision. If a user asks for /users/99 and that user exists but belongs to someone else, should you return 404 (pretend it doesn't exist) or 403 (admit it exists but deny access)? Returning 404 is often the more secure choice it doesn't reveal which IDs exist.

Designing the Users Resource

Let's build a complete CRUD API for a users resource. In a real app you'd use a database here we'll use an in-memory array to keep the focus on the API design.

GET /users β€” List all users

GET /users/:id β€” Get one user

POST /users β€” Create a new user

PUT /users/:id β€” Replace a user

DELETE /users/:id β€” Remove a user

Route Naming: The Conventions That Actually Matter

These conventions aren't enforced by any framework. They're just what every experienced developer expects, which is exactly why they matter:

Use nouns, not verbs in URLs.

  • /users not /getUsers, /createUser, /deleteUser

Use plural nouns for collections.

  • /users not /user

  • /posts not /post

Use URL parameters for specific resources.

  • /users/42 not /users?id=42

Use query strings for filtering, sorting, pagination.

  • /users?role=admin β€” filter by role

  • /users?sort=created_at&order=desc β€” sorted list

  • /users?page=2&limit=20 β€” pagination

Nested resources for relationships.

  • /users/42/posts β€” all posts by user 42

  • /users/42/posts/7 β€” a specific post by user 42

What most developers don't think about: versioning. When your API is public or consumed by mobile apps you don't control, you'll eventually need to change it in a breaking way. The standard solution is URL versioning: /api/v1/users, /api/v2/users. It's something you should add from the start, not retrofit later.

Error Consistency:

One thing that separates a professional API from a tutorial API: consistent error responses. Your errors should all look the same.

REST API design is largely a discipline of making decisions before you start coding and sticking to them. The decisions aren't hard: plural nouns, HTTP methods as verbs, correct status codes, consistent error shapes. None of these require advanced knowledge they just require intention.

Express.js gives you the minimum to implement all of this. No magic, no opinions just a router, middleware support, and req/res. The REST conventions layer on top cleanly.

Master one resource, get all the conventions right, and every other resource you add will look exactly the same. That's the whole point of REST: uniformity. Once a developer learns how one endpoint works, they understand how all of them work.

I’m currently deep-diving into the JavaScript, building projects and exploring the internals of the web. If you're on a similar journey or just love talking about JavaScript, let’s stay in touch!

Keep coding and keep building.