HomeBlogWeb DevelopmentCreate an HTTP Server with Node.js: Beginner's Guide

Create an HTTP Server with Node.js: Beginner's Guide

Published
05th Sep, 2023
Views
view count loader
Read it in
12 Mins
In this article
    Create an HTTP Server with Node.js: Beginner's Guide

    Node.js is a powerful open-source, cross-platform, back-end JavaScript runtime environment that runs on the Chrome’s V8 engine and executes JavaScript code outside a web browser. Node.js allows developers to use JavaScript in order to write command line tools and also for server-side scripting, which means running scripts server-side to produce dynamic web page content before the page is dispatched to the user's web browser. Consequently, Node.js represents a paradigm called "JavaScript everywhere" which simply put together represents a unified full stack web development around a common programming language, rather than the use of different languages for server-side and client-side scripts. 

    The most basic application to try out the same is the implementation of an HTTP(HyperText Transfer Protocol) web server. HTTP is a protocol, which is used for fetching resources like HTML documents and more. It is the most common foundation for any data exchange on the Web and is basically a client-server protocol, which means requests are triggered by the recipient, usually the Web browser. When we see a page in our browser, in the background we are making a request to another system over the internet, which provides us the webpage as a response. That system with which we are communicating via the internet is a web server.

    In this article we will cover a basic implementation of a simple HTTP server using NodeJS. A Node http server is the easiest way to get your hands on the same and practice a Node js web server. You can further explore the best course for Node.js which goes in full detail about the same.

    Creating HTTP Server

    For this instance we will assume that Node.js is installed in the system. Node.js supports creating web servers out of the box, which means a Node js web server can be directly created from a basic command set. 

    We will start by creating a Node simple http server, whose purpose will be to return a plain text back to the user. This will cover the key concepts required to set up a server, which in turn can be extrapolated to provide the necessary foundation to return further complex data formats like JSON. 

    First, it is required that we set up an environment, so for that we will be creating a folder called sampleServer, and create a file that is going to house the server. After this we need to open the file in an editor of our choice, and after that we start by loading the http module. This comes standard with all Node.js installations

    const http = require("http"); 

    The http module available with the Node js bundle contains the necessary functions to create the server, which we will check out later on. The next step is to define two constants, the host and port. This would refer to where our server is going to be bound to: 

    const host = 'localhost'; 
    const port = 8000; 

    As mentioned before, a web server accepts requests from different browsers and other types of clients. We can interact with a web server through a domain name, which is then translated to a respective system’s IP address by a DNS server. An IP address is a unique identifier sequence of numbers that identify a system on a network. 

    Localhost is a special private address that computer systems use to refer to themselves. It’s typically represented as the internal IP address 127.0.0.1 and it’s only available to the specific computer, not to any of the networks we are connected to. 

    Port is a number that is used by the servers as an endpoint to our IP addresses. In this example, we will be going forward with the port 8000 for our web server. Ports 8080 and 8000 are typically used as default ports in development and testing phases, and it is kind of an unsaid understanding amongst developers to use them rather than other available ports for HTTP servers. 

    When we bind our server to this specific host and port, we are able to reach our server by visiting http://localhost:8000 in a local browser. Now in order to verify that the server is created, we need to add a function, which in Node.js is called as a request listener. This function handles an incoming HTTP request and returns a respective HTTP response. This function has two specific arguments, a request object and a response object. The request object is responsible for capturing all the data of the HTTP request that’s incoming. The response object is responsible for returning HTTP responses from the server. 

    We will be returning a message "Hello from Server!", whenever someone accesses it. Let’s add that required function next: 

    const requestListener = function (req, res) { 
     res.writeHead(200); 
     res.end("Hello from Server!"); 
    }; 

    The function should usually be named based on its purpose.. Since this represents a generic sample case, we will use the generic name requestListener. 

    These request listener functions accept two specific arguments, namely request and response. In the above example, they are written as req and res, we can name them as per convenience. A Request object encapsulates the HTTP request sent by the user, which is the first argument. The HTTP response that is returned to the user is generated by interacting with the Response object which is the second argument. Please note that in case requestListener() does not use the req object, still it must be the first argument of the function.

    The first line res.writeHead(200), sets the necessary HTTP status code of the response. The HTTP status code indicates how a specific HTTP request was handled by the server. There are many responses like 404 representing not found, 501 representing failure etc. In this case, the status code value 200 corresponds to success. 

    The next line res.end("Hello from Server!"), writes the plain text response back to the client. This function is responsible for returning whatever data the server has to return. In our case, it’s returning plain text data. 

    Finally, we can now create our server and make use of our request listener: 

    The next line in the corresponding function, res.end("Hello from Server!") is responsible for writing the HTTP response back to the client that has requested it. This function handles any data returns provided by the server. In our example case, it’s returning text based data. 

    Lastly, we can now go ahead and create our server by making use of our request listener: 

    const server = http.createServer(requestListener); 
    server.listen(port, host, () => { 
     console.log(`Server is running on http://${host}:${port}`); 
    }); 

    In this example, in the first line, we create a new server object using the http module, using the createServer() function. This shows that the server accepts HTTP requests and passes them to the requestListener() function. 

    After the server is created, we need to bind it to a specific network address. It is done with the help of server.listen() method. It accepts three parameters: port, host, and a callback function that is triggered when the server starts to listen. 

    Note that all of the mentioned arguments are actually optional, but it is good practice to explicitly state which port and host are we using for the web server, as it helps to set up load balancing or a DNS alias, when required. The callback function also logs a message to the console so that we can know when the server started listening to the connections. 

    Now in order to test this we need to run the js file that we created :

    Node sample.js and we see this in the console 

    After running this, the Node.js server will continue to run. It will stop only if we manually terminate the process which is running the server or if it encounters an runtime error. 

    We can now communicate with the server using a separate terminal window, using cURL, a CLI tool used to transfer data to and from a network. We can directly use curl on the localhost address and get the result. 

    How the process happens is as follows :

    • We send a GET request to the server at http://localhost:8000 using Curl.
    • The Node.js server listens to connections from the localhost server address. 
    • The server then passed that request to the requestListener() function. 
    • The function returned the added text data with the status code 200, which implies OK.
    • The server then sent that response back to cURL, which is then displayed in the terminal. 

    Also you can check out the full stack web development bootcamp to work and experience everything in action. 

    Returning Content

    The response from the server is not always plain text, we can return HTML, Json, XML, CSV and other response formats as well. We can also return non text data like PDF, audio video etc. 

    Firstly to ensure this, we need to set the Content-Type header in our HTTP responses with whatever is the appropriate response type and ensure that res.end() should get the data in the right format. 

    In the following example we will see how we can return json data from the server. JSON stands for JavaScript Object Notation which is a text-based data exchange format. Although it is derived from JavaScript, it is very much language independent, allowing it to be used by any language which can parse it. JSON is most commonly used as a go to way to accept and return data with APIs, due to its lower data transfer size than legacy data exchange standards. 

    Let's create a new file with the template for the server 

    const http = require("http"); 
    const host = 'localhost'; 
    const port = 8000; 
    const requestListener = function (req, res) {}; 
    const server = http.createServer(requestListener); 
    server.listen(port, host, () => { 
     console.log(`Server is running on http://${host}:${port}`); 
    }); 

    Her we are returning a JSON response, so we will be modifying the requestListener() function to return the appropriate header :

    const requestListener = function (req, res) { 
     res.setHeader("Content-Type", "application/json"); 
    }; 

    The setHeader() method of the response object adds an HTTP header to the response. HTTP headers infer additional information that can be attached to both request or response. The res.setHeader() method needs two arguments, header’s name and its corresponding value. 

    The header ‘Content-Type’ is used to indicate the format of the data that’s being passed along with the request or response. Since we are going to use JSON, our Content-Type is application/json. 

    Now in order to return a sample JSON content to the user, we will have to Modify the file with some random json info: 

    const requestListener = function (req, res) { 
     res.setHeader("Content-Type", "application/json"); 
     res.writeHead(200); 
     res.end(`{"sample message": "This is a sample JSON response"}`); 
    }; 

    Here as well, we inform the user that the request was successful by returning the status code of 200. Note that in the response.end() call, our string argument contains a valid JSON. Following is the output. 

    Serving HTML Page from a File

    HTML( HyperText Markup Language) is the most common format to use in order to provide user interaction with a web server, using a web browser. It was created specifically for structured web content. All the web browsers support HTML content, as well as any style addition done with CSS. CSS is another front-end piece of web technology that enables us to change the overall aesthetics of our websites. 

    In order to return the html page, we have to specify the content type in the response object similar to what we had done in case of JSON in the previous example. 

    const requestListener = function (req, res) { 
     res.setHeader("Content-Type", "text/html"); 
     res.writeHead(200); 
     res.end(`<html><body><h2><Strong>This is HTML</h2></body></html>`); 
    }; 

    Once we run this JavaScript file and open http://localhost:8000 in a browser, we can see the html we returned. 

    However apart from manually adding the content we can also serve an html page from a file as the response. To serve HTML files, we load the HTML file with the help of ‘fs module’ and use its data when writing our HTTP response. 

    Let’s take the example of a sample html page we need to display. 

    <!DOCTYPE html> 
    <html> 
    <body> 
    <H1> This is an Html from a file </H1> 
    <p> This is the common ways to serve a page</p> 
    </body> 
    </html> 

    Now in order to import the file, we have to read it first, which is done using the fs module. 

    const http = require("http"); 
    const fs = require('fs').promises; 

    The fs module contains a readFile() function that is generally used to load HTML files. In order to keep up with the modern JavaScript practices, we import the promise variant of the call. Also it is better than callbacks, in various cases. 

    Now we need to modify the running js file with this info and return the page using then once finished. 

    const requestListener = function (req, res) { 
     fs.readFile(__dirname + "/samplePage.html") 
     .then(contents => { 
     res.setHeader("Content-Type", "text/html"); 
     res.writeHead(200); 
     res.end(contents); 
     }) 
    .catch(err => { 
     res.writeHead(500); 
     res.end(err); 
     return; 
     }); 
    }; 

    Here, the fs.readFile() method is used in order to load the file. It has 2 arguments ‘__dirname’ and ‘/samplePage.html’. The variable __dirname represents here the absolute path, where Node.js code is currently being executed. We can then append /samplePage.html to this path so that we can load the HTML file we want to serve. 

    Once the fs.readFile() promise resolves successfully, it will return the corresponding data. We next use the then() method to handle this followup case. The contents parameter is the one that contains the actual HTML file’s data. 

    It is advisable to use catch() method in pair with a promise as when a promise encounters an error, it is rejected, so it is better to handle these cases as well. The catch block accepts the error that fs.readFile() returns, and sets the status code to 500 which indicates a server internal error.and returns it to the user. 

    We can see the output once we run the file :

    Also, check for the blog post create HTTP request body using Node.js. 

    Handling Routes by HTTP Request Object

    Most websites or APIs we visit or use, usually have more than one url endpoint so that we can access various resources available in the same. A common example would be an inventory management case, one that might be used in maybe a warehouse. It would not only need to manage inventory data, but it would also manage quantity, manufacturer name etc, whatever data to be for cataloging and searching processes for convenience. 

    Even though the json data here - item name and manufacturer name are related in terms of the inventory they represent, they are different objects. In these cases, the response information of each object is usually stored on different endpoints. This gives an easy way to indicate to the current user of the API, what kind of data they are interacting with. 

    So far, we have not built any special routing logic inside the requestListener() function to handle requests whose URL contains other paths, so if we call http://localhost:8000/random ,Node.js will return the same response as that of http://localhost:8000 which is the default one. 

    In the following example, we will be creating a new server for a small inventory system, which can return 2 different types of data. Server’s address endpoint at /items, will provide a list of items with their respective quantities in JSON. The endpoint /manufacturers will provide a list of manufacturers information in JSON. Let’s begin by storing our JSON data in variables before the requestListener() function: 

    const items = JSON.stringify([ 
     { itemName: "Measuring Tape", manufacturer: "3M", quantity: 52 }, 
     { itemName: "DrillBit", manufacturer: "Bosch", quantity: 47 } 
    ]); 
    const manufacturers = JSON.stringify([ 
     { name: "3M", countryOfOrigin: "America", partnerSince: 2019 }, 
     { name: "Bosch", countryOfOrigin: "Germany", partnerSince: 2014 } 
    ]); 

    The items variable is a string that contains JSON for an array of item objects. Each item has a name, a manufacturer’s name, and the respective quantities. The manufacturers variable is a string that contains the JSON for an array of manufacturer objects. Each manufacturer has a name, a country of Origin, and since when they have been partners. 

    Now that we have added the data to the responses, we will get that in return. So for that, we need to modify the requestListener() function to route the requests to the correct routes, but first we have to ensure that every response from the server has the correct respective Content-Type header, in our case it is JSON. After this we have to return the right JSON depending on the URL path the user visits. In order to get a URL path from the request object, we need to access the property ‘url’. On the basis of this differentiator, we can create a switch statement on the request’s URL as follows: 

    const requestListener = function (req, res) { 
     res.setHeader("Content-Type", "application/json"); 
     switch (req.url) { 
     case "/items": 
     res.writeHead(200); 
     res.end(items); 
     break 
     case "/manufacturers": 
     res.writeHead(200); 
     res.end(manufacturers); 
     break 
     default: 
     res.writeHead(404); 
     res.end(JSON.stringify({error:"Resource not found"})); 
     } 
    } 

    Similar to what we did earlier, we set a response code as 200, to indicate a successful call, and we return the Json in that case. The Default case can be used to signify an error for the same. Here 404, which stands for resource not found, makes more sense. 

    If we test this against the curl URL call, we can see different returns for the calls. 

    We can see since we have added a default, it is being called in the case no path is given, this verifies all 3 cases/routes that we have mentioned. 

    You might also find it interesting to read about guide to Node.js history and versions article. 

    Conclusion

    The Node.js framework can be used in a very extensible and flexible way to develop web servers using the inbuilt ‘http’ module. We saw above how the application can be made to listen on a particular port and can send a response to the client whenever a request is made to the application. 

    The main power of using Node.js to create a Node web server is the flexibility it offers in terms of type of responses be it HTML, JSON, XML, CSV or the ability for routing, etc. We also saw the scalability of a Node simple http server, and what it can do.

    Also apart from this we also saw how to create an API that can use information provided in the request to determine what data should be sent as a part of its response. With this insight we can create scalable web servers that can handle a variety of requests and responses also at different endpoints, which is essential while creating APIs. Remember, you can further explore knowledgeHut’s best course for Node.js which goes in full detail about the same, and check out the full-stack web development bootcamp to work and experience everything in action. 

    Frequently Asked Questions (FAQs)

    1How can I make an HTTP Server?

    Most languages provide a basic support for running a simple http server, based on some inbuilt functions, like in Node.js, we use the http module and setup host and port and then using the createServer function in the http module, ask the server to listen to this port and host, like this below :

    const http = require("http"); 
    const host = 'localhost'; 
    const port = 8000; 
    const requestListener = function (req, res) {}; 
    const server = http.createServer(requestListener); 
    server.listen(port, host, () => { 
     console.log(`Server is running on http://${host}:${port}`); 
    }); 
    2How can I create an HTTP Server in Node.js?

    In Node.js, we use the http module and setup host and port and then using the createServer function in the http module, ask the server to listen to this port and host, like this below :

    const http = require("http"); 
    const host = 'localhost'; 
    const port = 8000; 
    const requestListener = function (req, res) {}; 
    const server = http.createServer(requestListener); 
    server.listen(port, host, () => { 
     console.log(`Server is running on http://${host}:${port}`); 
    }); 
    3What is an HTTP Server?

    An HTTP server is a program either independent or included as a part of any other component, that plays the role of a server in the client–server model by implementing the server part of the HTTP’s network protocols. An HTTP server waits for the incoming client requests which are sent by user agents like browsers, web crawlers, etc, and for each request it answers by replying with requested information, including the sending of the requested web resource, texts, media or with an HTTP error message. 

    4How should I start a Node.js server?

    Let's take the example wherein we have created a server listening to localhost at port 5000, the process to run it will be : 

    In the terminal run Node <filename.js> and then go to http://localhost:5000 or you can also use curl http://localhost:5000 to check the response. 

    5Is Node.js asynchronous?

    Yes, Node.js is an asynchronous event-driven JavaScript runtime environment which is designed to build scalable network applications. Here, asynchronous refers to all those JavaScript functions that are processed in the background without blocking any other request. 

    Profile

    Gaurav Roy

    Author

    I am an avid coder, software developer by profession and computer science post graduate from IIT(ISM) Dhanbad. I have 6.5+ yrs of development experience, working with cross platform mobile development in both iOS, Android and Web. I love to code and design robust systems, exploring and exploiting various cutting edge tech stacks available including Artificial Intelligence/machine Learning and evolutionary computing technologies, my post graduate thesis being based on the field. Apart from academics, I am a guitar player and singer.

    Share This Article
    Ready to Master the Skills that Drive Your Career?

    Avail your free 1:1 mentorship session.

    Select
    Your Message (Optional)

    Upcoming Web Development Batches & Dates

    NameDateFeeKnow more
    Course advisor icon
    Course Advisor
    Whatsapp/Chat icon