Node.js: Creating a REST API without Express

Table of Contents :
Why Create a REST API with Node.js?
Creating a REST API without using the
Express module in
Node.js offers several advantages,
particularly for understanding the fundamentals of
Node.js and the
HTTP protocol. By building an API
directly with the native http
module, you
gain a deeper understanding of requests,
responses, and
route management.
This approach reduces dependencies, which can be beneficial for lightweight projects or environments where size and performance are critical. Additionally, it provides complete control over the application's behavior, avoiding the overhead and abstraction introduced by frameworks like Express.
While this might require more development effort, it serves as an excellent learning exercise and a way to optimize custom-built applications.
The Code
To start a Node.js project and set up the environment for creating a REST API, begin by initializing the project with some basic commands.
First, run npm init
or
npm init -y
to generate a
package.json
file containing the project's metadata (name, version,
dependencies, etc.).
Next, create a main file, usually named
index.js
or server.js
, using
touch index.js
(or with a text editor). If
you plan to use development tools like
Nodemon for hot reloading, install them
with:
npm install nodemon --save-dev
Then, add a script in package.json
, for
example:
"start": "nodemon index.js"
Now, you can begin coding in the main file and build your project.
Imports & Constants
To create the REST API, we need to define two modules:
const http = require('http');
const url = require('url');
const PORT = 3000;
- http: The Node.js http module is a native module that allows you to create and manage HTTP servers, handling requests and responses directly.
- url: The Node.js url module enables parsing, formatting, and manipulating URL components.
We also define one constant:
- PORT: Specifies the port on which our Node.js server will listen.
REST API Routes
To create the HTTP server, we create a
variable and assign it
http.createServer(req, res)
:
const server = http.createServer((req, res) => {
});
Now, we can add different routes for the REST API:
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const method = req.method;
const pathname = parsedUrl.pathname;
if (pathname === '/api') {
switch (method) {
case 'GET':
handleGetRequest(res);
break;
case 'POST':
handlePostRequest(req, res);
break;
case 'PUT':
handlePutRequest(req, res);
break;
case 'DELETE':
handleDeleteRequest(res);
break;
case 'OPTIONS':
res.writeHead(204);
res.end();
break;
default:
res.writeHead(405);
res.end(JSON.stringify({ message: 'Method Not Allowed' }));
break;
}
}
});
And implement methods for each API verb:
const handleGetRequest = (res) => {
res.writeHead(200);
res.end(JSON.stringify({ message: 'GET request received' }));
};
const handlePostRequest = (req, res) => {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
res.writeHead(200);
res.end(JSON.stringify({
message: 'POST request received',
data: JSON.parse(body)
}));
});
};
const handlePutRequest = (req, res) => {
let body = '';
req.on('data', chunk => {
body += chunk.toString();
});
req.on('end', () => {
res.writeHead(200);
res.end(JSON.stringify({
message: 'PUT request received',
data: JSON.parse(body)
}));
});
};
const handleDeleteRequest = (res) => {
res.writeHead(200);
res.end(JSON.stringify({ message: 'DELETE request received' }));
};
Error Handling
To handle errors, simply add responses with error codes, such as:
- 405 for "Method Not Allowed"
- 404 for "Not Found"
This is reflected in the following code:
if (pathname === '/api') {
switch (method) {
case 'GET':
handleGetRequest(res);
break;
case 'POST':
handlePostRequest(req, res);
break;
case 'PUT':
handlePutRequest(req, res);
break;
case 'DELETE':
handleDeleteRequest(res);
break;
case 'OPTIONS':
res.writeHead(204);
res.end();
break;
default:
res.writeHead(405); // Here, the 405 error code
res.end(JSON.stringify({ message: 'Method Not Allowed' }));
break;
}
} else {
res.writeHead(404); // Here, the 404 error code
res.end(JSON.stringify({ message: 'Not Found' }));
}
CORS and Response Headers
It's necessary to add CORS and headers for proper server responses. This can be achieved by adding the following method:
const setCorsHeaders = (res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
};
And calling this method in createServer:
const server = http.createServer((req, res) => {
const parsedUrl = url.parse(req.url, true);
const method = req.method;
const pathname = parsedUrl.pathname;
setCorsHeaders(res); // Adding CORS here
res.setHeader('Content-Type', 'application/json'); // Setting Content-Type
if (pathname === '/api') {
switch (method) {
case 'GET':
handleGetRequest(res);
break;
case 'POST':
handlePostRequest(req, res);
break;
case 'PUT':
handlePutRequest(req, res);
break;
case 'DELETE':
handleDeleteRequest(res);
break;
case 'OPTIONS':
res.writeHead(204);
res.end();
break;
default:
res.writeHead(405);
res.end(JSON.stringify({ message: 'Method Not Allowed' }));
break;
}
} else {
res.writeHead(404);
res.end(JSON.stringify({ message: 'Not Found' }));
}
});
Starting the Server and Listening on PORT
Finally, to start the server on a specific port, use the
listen(port, next)
method:
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Run the command node server.js
to start the
server, and voilà, everything works!