Node.js: Creating a REST API without Express

Last update : January 26, 2025
Nodejs API REST
Node.js Native REST Logo

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!