Bytes

Routing and Serving Static Files

Last Updated: 22nd June, 2023

Overview

One of the key features of any web application is routing, which refers to the process of mapping incoming requests to the appropriate code that handles them. Additionally, serving static files is also a crucial aspect of web development. In this lesson, we will discuss how to build an HTTP server in NodeJS, including creating a simple routing system and serving static files.

Basics of Routing

Routing is the process of directing incoming HTTP requests to the appropriate handler function based on the requested URL and HTTP method. In a web application, routing is an essential aspect of handling user requests and displaying the appropriate content. Routing allows developers to organize their application's functionality into modular components, making it easier to maintain and scale the application. By routing incoming requests to the appropriate handler functions, developers can create a consistent user experience and avoid code duplication.

Creating a simple routing system based on request URLs and HTTP methods

In NodeJS, the built-in HTTP module provides the foundation for building an HTTP server. To create a simple routing system, we can use the http.createServer() method to create an HTTP server and listen for incoming requests. Here's an example:

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    // handle root request
  } else if (req.url === '/about') {
    // handle about request
  } else {
    // handle 404 error
  }
});

server.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

In this example, we're creating an HTTP server that listens for incoming requests on port 3000. When a request is received, we're checking the requested URL and handling it appropriately. If the requested URL is "/", we'll handle the root request. If the requested URL is "/about", we'll handle the about request. If the requested URL doesn't match any of our predefined routes, we'll handle a 404 error.

Serving static files (HTML, CSS, JS, images) from the file system

In addition to routing requests to handler functions, we may also need to serve static files such as HTML, CSS, JS, and images. NodeJS provides a built-in module called fs (file system) that allows us to read and write files on the server's file system. Here's an example of how to serve a static HTML file:

const http = require('http');
const fs = require('fs');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    // read index.html file and send it to the client
    fs.readFile('./public/index.html', (err, data) => {
      if (err) {
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        res.end('Internal Server Error');
      } else {
        res.writeHead(200, { 'Content-Type': 'text/html' });
        res.end(data);
      }
    });
  } else {
    res.writeHead(404, { 'Content-Type': 'text/plain' });
    res.end('Page not found');
  }
});

server.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

In this example, we're serving an index.html file located in the "./public" directory. When a request is made to the root URL ("/"), we're reading the index.html file using the fs.readFile()method and sending it to the client in the response body. We're setting the appropriate Content-Typeheader to tell the client that the response body is HTML.

If the file doesn't exist or there's an error while reading the file, we're sending a 500 Internal Server Error response to the client.

We can also serve other types of static files, such as CSS, JS, and images, using the same approach. We just need to set the appropriate Content-Type header based on the file type.

const http = require('http');
const fs = require('fs');
const path = require('path');

const server = http.createServer((req, res) => {
  const filePath = path.join(__dirname, 'public', req.url);

  fs.readFile(filePath, (err, content) => {
    if (err) {
      if (err.code === 'ENOENT') {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('File not found');
      } else {
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        res.end('Internal Server Error');
      }
    } else {
      const ext = path.extname(filePath);
      let contentType = 'text/html';

      switch (ext) {
        case '.css':
          contentType = 'text/css';
          break;
        case '.js':
          contentType = 'text/javascript';
          break;
        case '.png':
          contentType = 'image/png';
          break;
        case '.jpg':
          contentType = 'image/jpeg';
          break;
      }

      res.writeHead(200, { 'Content-Type': contentType });
      res.end(content);
    }
  });
});

server.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

In this example, we're using the path module to construct the file path based on the requested URL. We're then reading the file and setting the appropriate Content-Type header based on the file extension.

If the file doesn't exist or there's an error while reading the file, we're sending a 404 Not Found or 500 Internal Server Error response to the client.

Handling file paths, MIME types, and error responses (e.g., 404 Not Found)

When serving static files in NodeJS, it's important to handle file paths, MIME types, and error responses appropriately. The path module can be used to handle file paths, and the mime-types package can be used to determine the appropriate MIME type based on the file extension.

To handle error responses, we can use the res.writeHead() method to set the appropriate status code and Content-Type header. For example, if a requested file doesn't exist, we can send a 404 Not Found response:

const http = require('http');
const fs = require('fs');
const path = require('path');
const mime = require('mime-types');

const server = http.createServer((req, res) => {
  const filePath = path.join(__dirname, 'public', req.url);

  fs.readFile(filePath, (err, content) => {
    if (err) {
      if (err.code === 'ENOENT') {
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('File not found');
      } else {
        res.writeHead(500, { 'Content-Type': 'text/plain' });
        res.end('Internal Server Error');
      }
    } else {
      const contentType = mime.contentType(path.extname(filePath)) || 'text/plain';

      res.writeHead(200, { 'Content-Type': contentType });
      res.end(content);
    }
  });
});

server.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

In this example, we're using the mime-types package to determine the appropriate MIME type based on the file extension. If the MIME type can't be determined, we're setting the Content-Type header to 'text/plain' as a fallback.

Example: Building a basic web server that serves static files and handles custom routes

Now that we've covered the basic concepts of routing and serving static files in NodeJS, let's put it all together and build a basic web server that serves static files and handles custom routes. Here's an example:

const http = require('http');
const fs = require('fs');
const path = require('path');
const mime = require('mime-types');

const server = http.createServer((req, res) => {
  const filePath = path.join(__dirname, 'public', req.url);

  if (req.url.startsWith('/api')) {
    // handle API routes
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ message: 'Hello from the API' }));
  } else {
    // serve static files
    fs.readFile(filePath, (err, content) => {
      if (err) {
        if (err.code === 'ENOENT') {
          res.writeHead(404, { 'Content-Type': 'text/plain' });
          res.end('File not found');
        } else {
          res.writeHead(500, { 'Content-Type': 'text/plain' });
          res.end('Internal Server Error');
        }
      } else {
        const contentType = mime.contentType(path.extname(filePath)) || 'text/plain';

        res.writeHead(200, { 'Content-Type': contentType });
        res.end(content);
      }
    });
  }
});

server.listen(3000, () => {
  console.log('Server is listening on port 3000');
});

In this example, we're checking if the requested URL starts with '/api'. If it does, we're handling API routes and returning a JSON response. If it doesn't, we're serving static files using the fs.readFile() method and handling error responses as we discussed earlier.

To run this example, create a public directory in your project's root directory and add some static files, such as an index.html file, a styles.css file, and an image.jpg file. Then run the server using node server.js and navigate to http://localhost:3000 to see the served files. To test the API route, navigate to http://localhost:3000/api in your browser or send a GET request using a tool like Postman.

Conclusion

In conclusion, building an HTTP server in NodeJS requires a routing system and serving static files. Routing is crucial in handling user requests and displaying the appropriate content, and serving static files is necessary for delivering content such as HTML, CSS, JS, and images to clients. The built-in HTTP module and the file system (fs) module in NodeJS can be used to create a simple routing system and serve static files. The path module can be used to handle file paths, and the mime-types package can be used to determine the appropriate MIME type based on the file extension. By implementing these concepts, we can build a basic web server that serves static files and handles custom routes.

Module 5: Building an HTTP ServerRouting and Serving Static Files

Top Tutorials

Related Articles

  • Official Address
  • 4th floor, 133/2, Janardhan Towers, Residency Road, Bengaluru, Karnataka, 560025
  • Communication Address
  • Follow Us
  • facebookinstagramlinkedintwitteryoutubetelegram

© 2024 AlmaBetter