Skip to main content

Command Palette

Search for a command to run...

REST API Design Made Simple with Express.js

Updated
•7 min read•View as Markdown
REST API Design Made Simple with Express.js
S
I'm a passionate software engineer and full-stack MERN developer who loves to turn ideas into scalable, user-centric applications. I have hands-on experience in building modern web solutions using React, Node.js, Express.js, MongoDB, following clean architecture and best development practices. My experience in the Cognizant Healthcare Product Consulting (HPC) program has given me hands-on exposure to SQL, PL/SQL, U.S. healthcare payer systems and TriZetto Facets, and has helped me to further develop my skills in working with enterprise software in domain-driven environments. I enjoy tackling complex technical problems, constantly learning, and building reliable applications that deliver business value.

What does "REST API" actually mean?

Many beginners think REST is a library or a framework you install. That's not true.

REST is a set of rules for how a client and a server talk to each other over HTTP. Nothing to install, only rules to follow.

REST (Representational State Transfer) is a style of designing APIs where everything is a resource, and HTTP methods describe what you want to do with it.

An API is simply communication between a client and a server. The client asks. The server answers.


Analogy: The Restaurant

Think of a restaurant. We will use it for the whole article.

  • Customer = client (browser, mobile app)

  • Waiter = the API (carries requests and replies)

  • Kitchen = server and database

  • Dishes on the menu = resources

  • Type of order = HTTP method

  • Waiter's reply = status code

The customer never walks into the kitchen. They follow the menu and the waiter handles the rest. That is REST.

The menu is made of dishes. In REST, those dishes have a proper name: resources.


What are resources in REST?

A resource is a "thing" your app manages. Users, products, orders, posts.

In this article, our resource is users.

The golden rule: the URL names the thing (a noun), and the HTTP method says the action (a verb).

Bad route (verb in URL) Good route (REST style)
/getUsers GET /users
/createUser POST /users
/updateUser/5 PUT /users/5
/deleteUser/5 DELETE /users/5

Important Rule

Never put verbs in the URL. Use plural nouns (/users, not /user), and let the method carry the action.

If the URL is the dish, how do we tell the kitchen what to do with it? That is the job of HTTP methods.


Which HTTP methods do we use?

Four methods cover most of what a beginner needs. They map directly to CRUD.

Method CRUD In the restaurant Example route
GET Read "Show me what's available" GET /users
POST Create "Place a new order" POST /users
PUT Update "Change my existing order" PUT /users/2
DELETE Delete "Cancel my order" DELETE /users/2

Note

PUT replaces the whole resource, so you send the full object. Partial updates use PATCH, which we skip here.

The kitchen has done its work. Now the waiter must tell the customer what happened.


What do status codes tell us?

A status code is a three-digit number in every response. The first digit tells the story.

Range Meaning In the restaurant
2xx Success "Here is your food"
4xx Client made a mistake "That dish is not on the menu"
5xx Server failed "Sorry, the kitchen is on fire"

The five codes you will use most:

  • 200 OK: request worked, here is the data

  • 201 Created: a new resource was made

  • 400 Bad Request: the client sent wrong or missing data

  • 404 Not Found: that resource does not exist

  • 500 Internal Server Error: something broke on the server

Important Rule

If a user id does not exist, return 404. Do not return 200 with an empty body. The status code is part of the answer.

Now we know the menu, the orders and the replies. Let's watch one full trip from customer to kitchen and back.


How does one request travel?

Take this request: DELETE /users/2.

  1. Step 1: The client sends the request with a method and a URL.

  2. Step 2: Express matches it to the route app.delete("/users/:id").

  3. Step 3: The handler finds user 2 and removes it.

  4. Step 4: The server sends back a status code and, usually, JSON.

  5. Step 5: The client reads the status code first, then the body.


How do we build the users API in Express?

Here is the whole users resource. We store users in an array, because a database comes in a later article.

import express from "express";

const app = express();

app.use(express.json());

let users = [
  { id: 1, name: "Asha" },
  { id: 2, name: "Ravi" },
];

// GET all users
app.get("/users", (req, res) => {
  res.status(200).json(users);
});

// GET one user
app.get("/users/:id", (req, res) => {
  const user = users.find((u) => u.id === Number(req.params.id));

  if (!user) { 
    return res.status(404).json({
        error: {
            message: "User not found",
        },
    });
  }

  res.status(200).json(user);
});

// POST create a user
app.post("/users", (req, res) => {
  if (!req.body.name) {
    return res.status(404).json({
        error: {
            message: "Name is required",
        },
    });
  }

  const user = { id: Date.now(), name: req.body.name };

  users.push(user);

  res.status(201).json(user);
});

// PUT update a user
app.put("/users/:id", (req, res) => {
  const index = users.findIndex((u) => u.id === Number(req.params.id));

  if (index === -1) {
    return res.status(404).json({
        error: {
            message: "User not found",
        },
    });
  }

  users[index] = { id: users[index].id, name: req.body.name };
  
  res.status(200).json(users[index]);
});

// DELETE remove a user
app.delete("/users/:id", (req, res) => {
  const id = Number(req.params.id);

  if (!users.some((u) => u.id === id)) {
    return res.status(404).json({
        error: {
            message: "User not found",
        },
    });
  }

  users = users.filter((u) => u.id !== id);

  res.status(200).json({ message: "User deleted" });
});

app.listen(8080, () => console.log("Server running on port 8080"));

Notice the pattern. Same URL, different method, different action.

Run the server and try it from postman application:

GET http://localhost:3000/users

POST http://localhost:3000/users 
   Choose raw then enter down JSON data    
    {
        "name":"Meera"
    }

DELETE http://localhost:3000/users/2

http://localhost:3000/users/999

The last one returns 404 Not Found. We use to see the status line. We avoid other flags here, because confidence comes first.

Assignment

Try it yourself: Add a route that returns only users whose name starts with a given letter, e.g., the URL should be http://localhost:8080/users?startsWith=Aand the HTTP method should be GET.

Solution:
app.get("/users", (req, res) => {
  const { startsWith } = req.query;

if (!startsWith) { return res.status(200).json(users); }

const result = users.filter((u) => u.name.toLowerCase().startsWith(startsWith.toLowerCase()) );

res.status(200).json(result); });

Replace the earlier GET /users handler with this one. The URL stays /users, and the filter goes in the query string.


Conclusion

  • REST is a set of rules, not a library.

  • Resources are nouns in the URL, like /users.

  • HTTP methods carry the action: GET reads, POST creates, PUT updates, and DELETE removes.

  • Status codes tell the client what happened: 2xx worked, 4xx your mistake, 5xx our mistake.

If this felt like a lot, that's okay. What matters is understanding the flow: noun in the URL, verb in the method, and status code in the reply.

What's Next?

Our users live in an array, and they vanish when the server restarts. In the next article, Handling File Uploads in Express with Multer, we answer: how do we store files and images?


If you found this useful, drop a comment or a reaction.

More from this blog

Sahil Gupta | Web Development, Frontend, Backend & DevOps

52 posts

I'm a passionate software engineer and full-stack MERN developer who loves to turn ideas into scalable, user-centric applications. I have hands-on experience in building modern web solutions using React, Node.js, Express.js, MongoDB, following clean architecture and best development practices. My experience in the Cognizant Healthcare Product Consulting (HPC) program has given me hands-on exposure to SQL, PL/SQL, U.S. healthcare payer systems and TriZetto Facets, and has helped me to further dev