Building NodeJs API without ExpressJs or any other framework

I have been building NodeJs RESTful API with the help of ExpressJs and a ton of other node packages known as npm packagesfor a while now, and all has been going well. But for some reason recently, I began to wonder about the capability of NodeJs as a language on its own. Hence, I began to dig into NodeJs documentation found here. To document my findings and also put my learnings into practice, I decided to do what would normally be done with the help of a framework with just NodeJs alone.

Therefore, in this article, we will be building simple user management RESTful API without using any package, yes, no package!😅

Prerequisites

Install NodeJs on your local machine from https://nodejs.org/

Alright, let’s get coding… 🕺

create the project folder on your desktop or in any other folder you’ll like to house the project in, call it just-node-API (or any other name you wish to call it)

$ mkdir just-node-api
$ cd just-node-api

To initiate the project as a node project, run the following command:

$ npm init -y

This creates a file called package.json (a file that serves as a manifest for our project). Notice the flag -y that is in the command above, it allows you to initialize the node project using the default parameters.

Next, create a file called server.js

$ touch server.js

Add the following code to the file

const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = require('./route.js'); // imports the routing file
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

The server.js file is the one that handles the starting up of the server, the server will run at port 3000, also note that another file is required in the server.js file, that is the route.js file. This file will be created next.

Create the file by runningtouch route.js on your terminal. This file will handle the routing of the API endpoints to be created in this application.

Creation of the GET endpoint

For this endpoint, we will be using a dummy database (basically an array of data) stored in a file to be called userData.js, create the file in the root of the project, and populate it with the following data (remember to personalize it to fit your need/taste 😉)

module.exports = users = [

 {
   id: 1,
   name: 'Seyi',
   location: 'Buenos Aires'
 },
 {
   id: 2,
   name: 'David Khan',
   location: 'Argentina'
 },
 {
   id: 3,
   name: 'Isaac',
   location: 'Kwala lumpor'
 }
];

Inside the route.js file created earlier, add the following code

const http = require('http');
const url = require('url');
module.exports = http.createServer((req, res) => {
    var userOps = require('./controller.js');
    const reqUrl =  url.parse(req.url, true);
// GET endpoint
  if(reqUrl.pathname == '/users' && req.method === 'GET') {
    console.log('Request type: ' + req.method + ' Endpoint: ' + req.url);
    userOps.getUsers(req, res);
   }
 }
})

Notice that the HTTP and the URL modules were imported into the file above. These are inbuilt modules in Node.Js, the HTTP module allows you to use the HTTP server and client, and it supports many features of the protocol.

The URL module enables you to do URL resolution and parsing.

The line HTTP.createServer((req, res) is stating that a server will be created with the request called req and response called res.

Note that a file was required, the controller.js file, this is where the logic for the APIs will be written. we’ll create that in a bit.

The routing is done using the if statement, and it checks for the method being called and the pathname before calling the right function as imported from the controller.js file.

This file is exported from the route.js file using the module.exports which is what made it possible for it to be imported into the server.js file.

Now create the controller.js file using touch controller.js and add this code to it.

const url = require('url');
const users = require('./userData.js');
exports.getUsers = function(req, res) {
  const reqUrl = url.parse(req.url, true)
  var response = [
    {
      "message": "Here are the list of users "
    },
    users
  ];
  res.statusCode = 200;
  res.setHeader('content-Type', 'Application/json');
  res.end(JSON.stringify(response))
 }

The file imports the userData.js file created earlier because this is where the data to be fetched lives.

The getUsers function implements what will be returned after the GET ./users endpoint is hit. It basically crafts the message to be sent and sets the header, returns the status code, and stringifies the data response.

Now, on your terminal, run node server.js to start the server, you should get this

Server running at http://127.0.0.1:3000/

Open the link in a browser precisely sending this http://127.0.0.1:3000/user you should get this (if you followed along):

Image for post

Image for post

127.0.0.1:3000/users

Note: When you visit a link from your browser, you are carrying out a _GET_ request.

Creation of the POST endpoint

In creating this endpoint, head over to the route.js file, and add this code to the existing code in the file, immediately after the closing parenthesis of the If statement.

...
// POST endpoint
else if(reqUrl.pathname == '/user' && req.method === 'POST') {
   console.log('Request type: ' + req.method + ' Endpoint: ' + req.url);
   userOps.createUser(req, res);
}
...

This endpoint is calling the createUser function inside the controller.js file, let’s head over to the controller to write the function.

Add the following lines of code after the closing parenthesis of the getUsers function

exports.createUser = function(req, res) {
   body = '';

   req.on('data',  function (chunk) {
     body += chunk;
   });

   req.on('end', function () {
     postBody = JSON.parse(body);
     var response = [
       {
         "text": "User added successfully"
       },
       postBody
     ]

     res.statusCode = 201;
     res.setHeader('content-Type', 'Application/json');
     res.end(JSON.stringify(response))
   })
 }

This function operates for creating a new User, it posts the new user and returns a response.

req.on('data',  function (chunk) {
  body += chunk;
});

This is where the data being supplied is fed into the server, it comes in in streams, for info on how streams work in Node.Js, check here.

req.on('end', function() {...}) is called only after all the data has been streamed and the body is complete, it is then converted into JSON format by JSON.parse(body) so that the value in it can be used.

Then the response is returned just like we did in the GET endpoint.

Now, to test this endpoint, run node server.js on the terminal,

Using POSTMAN, let’s test out this POST request.

Image for post

Image for post

the response got from running POST 127.0.0.1:3000/user

Invalid Requests

As with many web applications, when a user visits an inexistent route, you don’t want to leave them hanging and wondering what the heck is going on with your app. So, to avoid that, we will also build a simple API that will act as our informative 404 API route.

Head over to the route.js file, add the following line of code after the last else if

// invalid URL
else {
  console.log('Request type: ' + req.method + ' Endpoint: ' + req.url);

  userOps.invalidUrl(req, res);
}

Now in the controller.js file, add the following code after the required statements.

const availableEndpoints = [
  {
    method: "GET",
    getUsers: "/users"
  },
  {
    method: "POST",
    createUser: "/user"
  }
]
...

next, in the same file, add the next set of code after the createUser function

exports.invalidUrl = function(req, res) {
   var response = [
     {
       "message": "Oops! that is a wrong endpoint, here are the available endpoints "
     },
     availableEndpoints
   ]

res.statusCode = 404;
   res.setHeader('content-Type', 'Application/json');
   res.end(JSON.stringify(response))
}

Now, let’s test the output also on Postman, start the server using

node server.js

Note that this function(the invalidUrl) will fire if any other endpoint is visited apart from the two endpoints catered for in this project.

Visiting GET 127.0.0.1:3000 will give us the following result

Image for post

Image for post

a response message for invalid Url

And finally, we have come to the end of this tutorial 😅

The code is available on github.com

Note: this tutorial is for exploration purpose 👀 , when developing apps, please kindly use any framework that will make your work easier and faster 😃.

Remember to like 😉 if this blog post was informative.

Big Ups to this blog from where I got this inspiration from.