# Building a Secure REST API with Node.js and Express

Modern web applications often depend on APIs to communicate between the frontend, backend, and databases. Whether you're building a dashboard, mobile application, or SaaS product, understanding how REST APIs work is an important backend skill.

In this article, we'll build a simple REST API using Node.js and Express.js, while following a structure that can later be extended with authentication and a database.

What We're Building

Our API will have endpoints for managing users:

```plaintext
GET     /api/users
GET     /api/users/:id
POST    /api/users
PUT     /api/users/:id
DELETE  /api/users/:id
```

The basic architecture looks like this:

```plaintext
Client
  │
  ▼
Express Server
  │
  ├── Routes
  │
  ├── Controllers
  │
  ├── Middleware
  │
  ▼
Database
```

1.  Create the Project
    

Start by creating a new Node.js project:

`mkdir node-rest-api cd node-rest-api npm init -y`

Install Express:

`npm install express`

For development, you can also install Nodemon:

`npm install --save-dev nodemon 2. Create the Server`

Create an app.js file:

```javascript
const express = require("express");

const app = express(); const PORT = 3000;

app.use(express.json());

app.get("/", (req, res) => { res.json({ message: "API is running 🚀" }); });

app.listen(PORT, () => { console.log(Server running on port ${PORT}); });
```

Run it:

`node app.js`

`Visit:`

`http://localhost:3000`

You should get:

{ "message": "API is running 🚀" } 3. Create Some Data

For now, we'll use an array instead of a database.

`let users = [ { id: 1, name: "Ajnas", email: "ajnas@example.com" }, { id: 2, name: "John", email: "john@example.com" } ]; 4. GET All Users`

We can create an endpoint that returns all users:

`app.get("/api/users", (req, res) => { res.json(users); });`

Request:

**<mark class="bg-yellow-200 dark:bg-yellow-500/30">GET /api/users</mark>**

Response:

`[ { "id": 1, "name": "Ajnas", "email": "ajnas@example.com" }, { "id": 2, "name": "John", "email": "john@example.com" } ] 5. GET a Single User`

Route parameters allow us to retrieve a specific user.

```javascript
app.get("/api/users/:id", (req, res) => { const id = Number(req.params.id);

const user = users.find(user => user.id === id);

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

res.json(user);
});
```

Now:

GET /api/users/1

returns:

`{ "id": 1, "name": "Ajnas", "email": "ajnas@example.com" }`

6\. Creating a User

For creating resources, we use POST.

```javascript
app.post("/api/users", (req, res) => { const { name, email } = req.body;

if (!name || !email) {
    return res.status(400).json({
        message: "Name and email are required"
    });
}

const newUser = {
    id: users.length + 1,
    name,
    email
};

users.push(newUser);

res.status(201).json(newUser);
```

});

The request body:

{ "name": "Charlie", "email": "charlie@example.com" }

The API responds with:

`{ "id": 3, "name": "Charlie", "email": "charlie@example.com" }`

7\. Updating a User

We can use PUT to update an existing resource:

```javascript
app.put("/api/users/:id", (req, res) => { const id = Number(req.params.id);

const user = users.find(user => user.id === id);

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

user.name = req.body.name ?? user.name;
user.email = req.body.email ?? user.email;

res.json(user);
```

});

This lets us update only the fields we provide.

8.  Deleting a User
    

Finally, we can implement DELETE:

```javascript
app.delete("/api/users/:id", (req, res) => { const id = Number(req.params.id);

const exists = users.some(user => user.id === id);

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

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

res.json({
    message: "User deleted successfully"
});
```

}); A Better Project Structure

Once an application grows, keeping everything inside app.js becomes difficult.

A more maintainable structure could look like:

```plaintext
node-rest-api/
│
├── controllers/
│   └── userController.js
│
├── routes/
│   └── userRoutes.js
│
├── middleware/
│   └── errorHandler.js
│
├── models/
│   └── userModel.js
│
├── app.js
├── package.json
└── .env
```

This separation makes the application easier to maintain and extend.

What's Next?

The array we're using isn't suitable for a real production application.

The next step would be connecting the API to a database such as PostgreSQL or MongoDB.

From there, we could add:

```plaintext
Database
   ↓
Authentication
   ↓
Authorization
   ↓
Input Validation
   ↓
Error Handling
   ↓
Rate Limiting
   ↓
Logging
   ↓
Production Deployment
```

That's where a simple REST API starts becoming a real backend application.

Final Thoughts

Building a REST API is one of those projects that looks simple at first but teaches a lot about backend development.

You learn how HTTP methods work, how requests and responses are structured, how routing works, how to handle errors, and eventually how different parts of a backend application communicate.

I'm still exploring backend development myself, and projects like this are helping me understand what happens behind the interface of the applications we use every day.

More of my projects and experiments:

[ajnasahammed.com](https://ajnasahammed.com/best-web-developer-in-malappuram/)
