đ Creating a Simple REST-like API with JSON using the Node.js http Module
Introduction
A REST-like API allows applications to communicate by exchanging data over HTTP using standard methods such as GET, POST, PUT, and DELETE. In this tutorial, you'll build a simple JSON API using Node.js's built-in http module without relying on external frameworks. The API will manage an in-memory collection of users and demonstrate the fundamentals of RESTful application development.
Information
This tutorial stores data in memory using a JavaScript array. All data is lost when the server restarts, making this approach suitable for learning and prototyping rather than production use.
Learning Objectives
- Create an HTTP server using the http module.
- Build REST-like endpoints using different HTTP methods.
- Send and receive JSON data.
- Implement CRUD (Create, Read, Update, Delete) operations.
- Return meaningful HTTP status codes.
Understanding REST-like APIs
A REST-like API organizes resources using URLs and HTTP methods. Each method performs a specific operation on a resource.
| HTTP Method | Endpoint | Operation |
|---|---|---|
| GET | /users | Retrieve all users. |
| POST | /users | Create a new user. |
| PUT | /users?id=1 | Update an existing user. |
| DELETE | /users?id=1 | Delete a user. |
Project Structure
đ rest-api
đ server.js
đ package.json (optional)
Creating the API Server
server.js
const http = require("http");
const users = [];
const server = http.createServer((req, res) => {
const url = new URL(req.url, "http://localhost:3000");
res.setHeader("Content-Type", "application/json");
// GET /users
if (url.pathname === "/users" && req.method === "GET") {
return res.end(JSON.stringify(users));
}
// POST /users
if (url.pathname === "/users" && req.method === "POST") {
let body = "";
req.on("data", chunk => {
body += chunk;
});
req.on("end", () => {
try {
const user = JSON.parse(body);
users.push(user);
res.writeHead(201);
res.end(JSON.stringify({
message: "User created",
data: user
}));
} catch {
res.writeHead(400);
res.end(JSON.stringify({
error: "Invalid JSON"
}));
}
});
return;
}
// PUT /users?id=1
if (url.pathname === "/users" && req.method === "PUT") {
const id = Number(url.searchParams.get("id"));
let body = "";
req.on("data", chunk => {
body += chunk;
});
req.on("end", () => {
try {
const updatedUser = JSON.parse(body);
const index = users.findIndex(user => user.id === id);
if (index === -1) {
res.writeHead(404);
return res.end(JSON.stringify({
error: "User not found"
}));
}
users[index] = {
...users[index],
...updatedUser
};
res.end(JSON.stringify(users[index]));
} catch {
res.writeHead(400);
res.end(JSON.stringify({
error: "Invalid JSON"
}));
}
});
return;
}
// DELETE /users?id=1
if (url.pathname === "/users" && req.method === "DELETE") {
const id = Number(url.searchParams.get("id"));
const index = users.findIndex(user => user.id === id);
if (index === -1) {
res.writeHead(404);
return res.end(JSON.stringify({
error: "User not found"
}));
}
users.splice(index, 1);
return res.end(JSON.stringify({
message: "User deleted"
}));
}
res.writeHead(404);
res.end(JSON.stringify({
error: "Route not found"
}));
});
server.listen(3000, () => {
console.log("Server running at http://localhost:3000");
});Request Processing Flow
đ Client Sends Request
đ Check URL Path
đ Check HTTP Method
Route Matches
Route Does Not Match
âī¸ Perform CRUD Operation
đ¨ Return JSON Response
â Return 404 Response
Testing the Endpoints
Create a User
POST /users
POST /users HTTP/1.1
Host: localhost:3000
Content-Type: application/json
{
"id": 1,
"name": "Alice",
"email": "alice@example.com"
}Retrieve All Users
GET /users
GET /users HTTP/1.1
Host: localhost:3000Update a User
PUT /users?id=1
PUT /users?id=1 HTTP/1.1
Host: localhost:3000
Content-Type: application/json
{
"name": "Alice Johnson"
}Delete a User
DELETE /users?id=1
DELETE /users?id=1 HTTP/1.1
Host: localhost:3000Using fetch()
GET Request
Fetch users
fetch("http://localhost:3000/users")
.then(response => response.json())
.then(data => {
console.log(data);
});POST Request
Create user
fetch("http://localhost:3000/users", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
id: 2,
name: "Bob",
email: "bob@example.com"
})
})
.then(response => response.json())
.then(data => console.log(data));CRUD Operation Flow
Users Collection
â POST â Add User
đ GET â Read Users
âī¸ PUT â Update User
đī¸ DELETE â Remove User
HTTP Status Codes
| Status Code | Meaning | Usage |
|---|---|---|
| 200 | OK | Successful GET, PUT, or DELETE request. |
| 201 | Created | New resource created successfully. |
| 400 | Bad Request | Malformed JSON or invalid input. |
| 404 | Not Found | Unknown route or missing user. |
| 500 | Internal Server Error | Unexpected server-side error. |
Advantages
- No external dependencies.
- Demonstrates the fundamentals of HTTP and REST concepts.
- Ideal for learning request handling and JSON processing.
- Easy to extend with additional endpoints.
Limitations
- Data is stored only in memory.
- Routes are manually implemented.
- No built-in middleware or validation.
- Not suitable for large production applications.
Warning
This example is intended for educational purposes. Production APIs should use persistent databases, comprehensive input validation, authentication, authorization, and structured error handling.
Best Practices
- Use meaningful HTTP status codes.
- Validate incoming request data before processing.
- Handle malformed JSON using try...catch.
- Return consistent JSON response structures.
- Separate routing, business logic, and data access into different modules as the application grows.
Best Practice
In RESTful APIs, resource URLs should represent nouns (such as /users), while HTTP methods should define the action to perform. This convention leads to APIs that are intuitive, predictable, and easier to maintain.
Official Documentation
Node.js HTTP Module Documentation
Summary
Summary
You created a simple REST-like JSON API using the Node.js http module. The API supports basic CRUD operations with GET, POST, PUT, and DELETE, processes JSON request bodies, stores data in memory, returns appropriate HTTP status codes, and demonstrates the core principles of RESTful web service development without external frameworks.