Creating a Simple Web Server

Setting the Stage: What You Need

Before we dive in, make sure you have Node.js and npm (Node Package Manager) installed on your computer.1 You can download them from the official Node.js website. npm comes bundled with Node.js, so you get both in one go!

Building a Basic Server with Raw Node.js (The Hard Way) βš™οΈ

Let's first see how you could build a web server using just the built-in tools of Node.js. This will help you appreciate how Express simplifies things later.

  1. Create a new folder for your project (e.g., my-first-server).

  2. Open your terminal or command prompt, navigate to this folder, and create a file named server.js.

  3. Paste the following code into server.js:

    JavaScript

     const http = require('http');
    
     const server = http.createServer((req, res) => {
       res.writeHead(200, { 'Content-Type': 'text/plain' });
       res.end('Hello from Node.js!');
     });
    
     const port = 3000;
     server.listen(port, () => {
       console.log(`Server listening on port ${port}`);
     });
    
  4. Run your server by typing node server.js in your terminal and pressing Enter.

  5. Open your web browser and go to http://localhost:3000. You should see "Hello from Node.js!" displayed.

See all that code just to say "Hello"? Now imagine handling different pages or requests! It can get complicated quickly.

Enter Express: The Superhero for Web Servers! πŸ’ͺ

Express is a popular framework built on top of Node.js.2 It provides a clean and organized way to build web applications and APIs.

  1. In your project folder, if you haven't already, initialize a Node.js project by running:

    Bash

     npm init -y
    

    This creates a package.json file that keeps track of your project's dependencies.

  2. Now, install Express by running:

    Bash

     npm install express
    
  3. Create a new file named app.js (or whatever you prefer) and add the following code:

    JavaScript

     const express = require('express');
     const app = express();
     const port = 3000;
    
     app.get('/', (req, res) => {
       res.send('Hello from Express!');
     });
    
     app.listen(port, () => {
       console.log(`Server listening on port ${port}`);
     });
    
  4. Run this server using node app.js in your terminal.

  5. Open your browser to http://localhost:3000. You should now see "Hello from Express!".

Notice how much simpler the Express code is for the same basic output!

Creating Routes and Handling Requests πŸ—ΊοΈ

Routes are like the different addresses or paths on your website (e.g., the homepage, an about page, etc.). In Express, you define how your server should respond when a user visits these different routes.3

Handling Requests means determining what to do when the server receives a request from a user (like clicking a link or submitting a form).4

Here's how you can define different routes in Express:

const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('This is the homepage!');
});

app.get('/about', (req, res) => {
  res.send('This is the about page.');
});

app.get('/contact', (req, res) => {
  res.send('Contact us at contact@example.com');
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

Now, if you run this and go to http://localhost:3000/about, you'll see "This is the about page." Similarly, http://localhost:3000/contact will show the contact information.

Middleware: The Helpful Assistants πŸ§‘β€πŸ³

Imagine a busy restaurant kitchen. The chef (your route handler) focuses on cooking the main dish. But before the food reaches the customer, it might go through other stations: a prep station, a plating station, etc. Middleware in Express is like these intermediate stations.

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application's request-response cycle.5 They can perform various tasks like:

  • Logging information about the request.

  • Authenticating users.

  • Parsing request data (like form submissions).6

  • Adding headers to the response.7

Here's a simple example of a middleware that logs every incoming request:

JavaScript

const express = require('express');
const app = express();
const port = 3000;

// Our first middleware
const logger = (req, res, next) => {
  console.log(`Received a ${req.method} request at ${req.url}`);
  next(); // Pass control to the next middleware or route handler
};

// Use the middleware for all routes
app.use(logger);

app.get('/', (req, res) => {
  res.send('Homepage with logging!');
});

app.get('/about', (req, res) => {
  res.send('About page with logging.');
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

If you run this and visit the homepage or the about page, you'll see a log message in your terminal for each request. The next() function is crucial; it tells Express to move on to the next middleware or the final route handler.

You can also create middleware that only applies to specific routes:

const express = require('express');
const app = express();
const port = 3000;

const authenticate = (req, res, next) => {
  // In a real application, you'd check for authentication here
  const isAuthenticated = true;
  if (isAuthenticated) {
    next();
  } else {
    res.status(401).send('Unauthorized');
  }
};

app.get('/admin', authenticate, (req, res) => {
  res.send('Welcome to the admin area!');
});

app.get('/public', (req, res) => {
  res.send('This is a public page.');
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

In this example, the /admin route uses the authenticate middleware. Only if isAuthenticated is true (in a real scenario, this would involve checking user credentials) will the user see "Welcome to the admin area!". Visiting /public doesn't go through the authenticate middleware and will always show "This is a public page.".

URL Parameters vs. Query Strings πŸ€”

When you visit a website, you often see information in the URL after the main address. There are two common ways to pass data through the URL: URL parameters and query strings.8

URL Parameters are used to identify a specific resource.9 They are part of the path itself. Think of them like the unique number of a product on an online store.

Example: /users/123 (Here, 123 might be the ID of a specific user).

In Express, you can access URL parameters using req.params:

const express = require('express');
const app = express();
const port = 3000;

app.get('/products/:id', (req, res) => {
  const productId = req.params.id;
  res.send(`Details for product with ID: ${productId}`);
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

If you go to http://localhost:3000/products/456, you'll see "Details for product with ID: 456".

Query Strings are used to pass additional data to the server.11 They appear after a question mark ? in the URL, with key-value pairs separated by ampersands &. Think of them like filters or search terms.

Example: /search?query=books&sort=price (Here, query is "books" and sort is "price").

In Express, you can access query strings using req.query:

const express = require('express');
const app = express();
const port = 3000;

app.get('/search', (req, res) => {
  const searchQuery = req.query.query;
  const sortOption = req.query.sort;
  res.send(`Searching for: ${searchQuery}, sorted by: ${sortOption}`);
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});

If you go to http://localhost:3000/search?query=laptops&sort=rating, you'll see "Searching for: laptops, sorted by: rating".

Suggestions for Your Next Steps πŸͺœ

  • Explore more HTTP methods: We've mainly used app.get(). Learn about app.post(), app.put(), and app.delete() for handling different types of requests (e.g., submitting forms, updating data, deleting data).12

  • Work with HTML: Instead of just sending plain text, learn how to send HTML files as responses to create actual web pages.13

  • Learn about Templating Engines: For more dynamic HTML generation, look into templating engines like EJS or Handlebars.14

  • Dive deeper into Middleware: Explore built-in middleware in Express (like express.json() for handling JSON data) and learn how to create more complex custom middleware.

  • Build a small project: The best way to learn is by doing! Try building a simple to-do list application or a basic blog using Node.js and Express.

Building web servers might seem a bit magical at first, but with Node.js and Express, you have powerful tools at your fingertips. Keep practicing, keep exploring, and soon you'll be creating your own amazing web applications! ✨

Data Flow :

0
Subscribe to my newsletter

Read articles from Syed Wasif Hussain directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Syed Wasif Hussain
Syed Wasif Hussain