By Md. Sabuj Sarker | 5/31/2018 | General |Beginners

Node.js Backend Development - Urls, Methods, & Forms

Node.js Backend Development - Urls, Methods, & Forms

In the previous article we discussed response objects and various useful methods and attributes connected to it. I skipped less used methods and attributes. In this article we are going to learn how to work with URLs, request methods, and forms. You can find the code of the previous article on the Github repository Learn Node.js With Sabuj. Browse to the branch prefixed with 004_ to browse the code of the previous article. You can find the code of this article on the branch named "005_urls_methods_formst".

Working with URLs

Currently, our Node.js application returns the same response no matter what URL is requested. But, in the future we will improve our application to react differently in different situations.

We can get the requesting URL from the request object passed to the request processing function by accessing the url attribute of the object. But a URL has multiple parts including scheme, host, port, path, query string, and fragment identifier. We need them separately.

To get the components of a URL separately we need to parse it. In node we have a built-in module called url to carry out URL related operations. In this module we have a function called parse() that will return an object containing different parts of the URL.

Let's modify our code to work with URL components. For now, we will just output some of the URL components on the console.

var fs = require('fs');
var url = require('url');

exports.serveRequests = function(request, response){
   const url_comps = url.parse(request.url);
   // url data printing
   console.log("Requesting URL: " + request.url);
   console.log("Protocol Used: " + url_comps.protocol);
   console.log("Host: " + url_comps.host);
   console.log("Path: " + url_comps.path);
   // < url data printing
   fs.readFile('html/home.html', function (error, file_data){
       if (error){
           response.writeHead(500, "Internal Server Error",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write("<b>Something Went Terribly Wrong</b>", "utf8");
           response.end();    
       }else{
           response.writeHead(200, "All is well",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write(file_data, "utf8");
           response.end();
       } 
   });
};

Fire up the terminal, start the app with node main.js, go to the browser, and browse to the url http://localhost:5000/my_url_path. You will see the following output:

Requesting URL: /my_url_path
Protocol Used: null
Hostname: null
Path: /my_url_path

Notice that protocol and hostname are null. request.url does not provide a fully qualified URL, it only provides the path (along with the query string). Also remember that fragment identifier is not sent to the server—it lives and dies in the browser (or the the user agent).

Working with Methods

When we are browsing a web page, downloading an image or some similar operation, it is usually a GET operation. That means the method of the operation is "GET." When we are submitting a form, it can be either through a "GET" or "POST" operation. When there is a file upload involved it is obviously a "POST" operation. There are other types of request methods that we may discuss in the future. We the programmers define what methods to use, depending on the situation.

To find out what method was used to request a resource, use the method attribute on the request object. In the future, when we will perform file uploading or complex form processing, we will use conditional blocks to process GET and POST methods differently. For now, let's just print the data on the console.

var fs = require('fs');
var url = require('url');

exports.serveRequests = function(request, response){
   const url_comps = url.parse(request.url);
   // url data printing
   console.log("Requesting URL: " + request.url);
   console.log("Protocol Used: " + url_comps.protocol);
   console.log("Hostname: " + url_comps.hostname);
   console.log("Pathname: " + url_comps.pathname);
   console.log("Method used: " + request.method);
   console.log("\n");
   // < url data printing
   fs.readFile('html/home.html', function (error, file_data){
       if (error){
           response.writeHead(500, "Internal Server Error",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write("<b>Something Went Terribly Wrong</b>", "utf8");
           response.end();    
       }else{
           response.writeHead(200, "All is well",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write(file_data, "utf8");
           response.end();
       } 
   });
};

Restart the application, go to browser and hit the refresh button, you will see the following output:

Requesting URL: /my_url_path
Protocol Used: null
Hostname: null
Pathname: /my_url_path
Method used: GET

Working with Forms

Working with forms is a very fundamental operation in modern web applications. The simplest form that is usually seen is a single text box search form. In this article we are not going to work with complex forms, neither are we going to create a file upload form. Let's create an HTML file named form.html in our html directory that will contain the following code.

<!doctype html>
<html>
   <head>
       <title>Learning Node.js with Sabuj</title>
   </head>
   <body>
       <form action="/submit-form" method="GET">
           <h1>My simple form</h1>
           Name: <input type="text" name="name">
           <br/>
           Name: <input type="text" name="profession">
           <br/>
           <button type="submit"> SubmiT </button>
       </form>
   </body>
</html>

Currently we cannot load this HTML on the browser as our application only serves one file no matter what URL is requested. So, we will have to act conditionally. We can smell the future complexity in the code regarding different URLs and associated HTML files. So, we need to separate our concerns. I am creating a separate function that will be responsible for reading files and sending the response. It will accept file names and the response object. It looks like below:

function plainFileResponse(file_name, response){
   fs.readFile(file_name, function (error, file_data){
       if (error){
           response.writeHead(500, "Internal Server Error",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write("<b>Something Went Terribly Wrong</b>", "utf8");
           response.end();    
       }else{
           response.writeHead(200, "All is well",
               {
                   'Content-Type': 'text/html'
               }
           );
           response.write(file_data, "utf8");
           response.end();
       } 
   });
}

Now from the serveRequest() we can conditionally check the URL pathname and send response accordingly.

exports.serveRequests = function(request, response){
   const url_comps = url.parse(request.url);
   // url data printing
   console.log("Requesting URL: " + request.url);
   console.log("Protocol Used: " + url_comps.protocol);
   console.log("Hostname: " + url_comps.hostname);
   console.log("Pathname: " + url_comps.pathname);
   console.log("Method used: " + request.method);
   console.log("\n");
   // < url data printing
   if (url_comps.pathname === "/form.html"){
       plainFileResponse('html/form.html');
   }else if(url_comps.pathname === "/submit-form"){
       handleSimpleForm(request, response);
   }else{
       plainFileResponse('html/home.html');
   }
};

Notice that we have a new requirement of handleSimpleForm() that will be responsible for handling our form written above. We just want to send back the data that was sent to us.

function handleSimpleForm(url_comps, request, response){
   var params = url_comps.query;
   var name = params['name'];
   var profession = params['profession'];
   var result = "Profession: " + profession + "\n" + "Name: " + name + "\n"
   response.writeHead(200, "All is well",
               {
                   'Content-Type': 'text/plain'
               }
           );
           response.write(result, "utf8");
           response.end();
}

Restart the application and browse to http://localhost:5000/form.html, input data into the form and hit submit. You will see results like below:

Profession: Engineer
Name: Sabuj

Conclusion

We are advancing into creating a full featured web application. We are not using frameworks from the beginning. Instead, we are doing the job with raw Node.js code. This is the best way to go to learn properly. Keep practicing with Node.js and keep your eyes open for new posts.

 

Previous article: Working with Responses

Next article: Implementing Routing

 

About the Author

My name is Md. Sabuj Sarker. I am a Software Engineer, Trainer and Writer. I have over 10 years of experience in software development, web design and development, training, writing and some other cool stuff including few years of experience in mobile application development. I am also an open source contributor. Visit my github repository with username SabujXi or visit my personal website at www.sabuj.me.

By Md. Sabuj Sarker | 5/31/2018 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now