# Node.js, Express and REST APIs — Build Your First Backend

Source: https://skills101.in/learn/web-development/node-express-rest-api — Skills101 free tutorial (Web Development). Updated 2026-11-09.

**Node.js** runs JavaScript outside the browser — on servers. **Express** is a small framework that makes building web servers and **REST APIs** easy.

![A React app calls fetch, the Express API handles GET /api/courses, queries the database and returns rows as JSON; the table lists GET, POST, PUT and DELETE routes for /api/courses](https://skills101.in/learn-img/web-development/rest-flow.svg)

## 1. Node.js basics

```javascript
const fs = require("fs");
const path = require("path");
const os = require("os");

const file = path.join(os.tmpdir(), "skills101-demo.txt");
fs.writeFileSync(file, "Hello from Node");
console.log(fs.readFileSync(file, "utf8").toUpperCase());
fs.unlinkSync(file);
console.log(typeof process.version === "string" ? "running on Node" : "?");
```

```text
HELLO FROM NODE
running on Node
```

- **npm** installs packages: `npm init -y`, then `npm install express`.
- `package.json` lists your dependencies and scripts.

## 2. Your first Express API

```javascript
// server.js
const express = require("express");
const app = express();
app.use(express.json());                     // parse JSON request bodies

let courses = [
  { id: 1, title: "DSA in Java", price: 4999 },
  { id: 2, title: "SQL Basics", price: 0 },
];

app.get("/api/courses", (req, res) => {
  const { maxPrice } = req.query;             // ?maxPrice=1000
  const list = maxPrice ? courses.filter((c) => c.price <= Number(maxPrice)) : courses;
  res.json(list);
});

app.get("/api/courses/:id", (req, res) => {
  const course = courses.find((c) => c.id === Number(req.params.id));
  if (!course) return res.status(404).json({ error: "Course not found" });
  res.json(course);
});

app.post("/api/courses", (req, res) => {
  const { title, price } = req.body;
  if (!title || typeof price !== "number") {
    return res.status(400).json({ error: "title and numeric price are required" });
  }
  const course = { id: courses.length + 1, title, price };
  courses.push(course);
  res.status(201).json(course);
});

app.delete("/api/courses/:id", (req, res) => {
  courses = courses.filter((c) => c.id !== Number(req.params.id));
  res.status(204).end();
});

app.listen(3000, () => console.log("API on http://localhost:3000"));
```

Run with `node server.js`, then open `http://localhost:3000/api/courses`.

| Part | Example | Read with |
|---|---|---|
| Route param | `/api/courses/7` | `req.params.id` |
| Query string | `/api/courses?maxPrice=1000` | `req.query.maxPrice` |
| JSON body | `{ "title": "React" }` | `req.body.title` |

## 3. REST design rules

- **Nouns** in URLs, **HTTP methods** as verbs: `GET /courses`, not `/getCourses`.
- Plural resources: `/courses`, `/courses/7`, `/courses/7/lessons`.
- Correct **status codes**: 200 OK, 201 Created, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 500 Server Error.
- Return **JSON** consistently, including errors (`{ "error": "…" }`).

## 4. Middleware

Middleware are functions that run **before** your route handler — for logging, authentication, parsing:

```javascript
function logger(req, res, next) {
  console.log(req.method, req.url);
  next();                        // pass control to the next middleware/route
}

function requireLogin(req, res, next) {
  if (!req.headers.authorization) return res.status(401).json({ error: "Please log in" });
  next();
}

app.use(logger);
app.post("/api/enquiries", requireLogin, (req, res) => { /* … */ });
```

## 5. Connecting a database

In real apps, replace the in-memory array with a database using a library or ORM:
- PostgreSQL / MySQL → `pg`, `mysql2`, or **Prisma** (what Skills101 uses)
- MongoDB → **Mongoose**

```javascript
// with Prisma (example)
app.get("/api/courses", async (req, res) => {
  const courses = await prisma.course.findMany({ where: { published: true } });
  res.json(courses);
});
```

## 6. Security and deployment checklist

- **Validate every input** on the server (types, lengths, formats).
- **Never** build SQL by joining strings — use parameterised queries / an ORM (prevents SQL injection).
- Store passwords **hashed** (bcrypt/argon2), never plain.
- Keep secrets in **environment variables** (`process.env.DATABASE_URL`), not in code or GitHub.
- Enable **CORS** only for your own frontend's domain.
- Deploy on Render, Railway, a VPS with nginx + PM2, or similar.

## Common mistakes

- Forgetting `app.use(express.json())`, so `req.body` is undefined.
- Sending a response twice (missing `return` before `res.status(...)`).
- Returning 200 for errors.

## Quick recap

- Node runs JS on the server; npm manages packages.
- Express: `app.get/post/put/delete(path, handler)`, `req.params`, `req.query`, `req.body`, `res.status().json()`.
- REST: nouns + HTTP verbs + correct status codes + JSON.
- Middleware with `next()`; validate input, hash passwords, use env variables.


Practice quiz and free certificate: https://skills101.in/learn/web-development/node-express-rest-api