How to handle HTTP GET requests in Node.js

How to handle HTTP GET requests in Node.js

Setting up a basic HTTP server in Node.js is surprisingly simpler. The built-in http module allows you to create a server that can handle requests and send responses. Here’s a simple example to get you started.

const http = require('http');

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello, World!n');
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(Server running at http://localhost:${PORT}/);
});

This code creates an HTTP server that listens on port 3000. When you access this server via a browser or a tool like curl, it responds with “Hello, World!”. It’s a good starting point to understand how Node.js handles requests and responses.

You can easily extend this server to handle different routes. For example, you might want to respond differently based on the URL path. Here’s how you can modify the server to handle different paths.

const http = require('http');

const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Welcome to the homepage!n');
  } else if (req.url === '/about') {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('About us page.n');
  } else {
    res.statusCode = 404;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Page not found.n');
  }
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(Server running at http://localhost:${PORT}/);
});

With this setup, hitting the root URL will show a welcome message, while accessing ‘/about’ will show a different message. For any other path, the server responds with a 404 status, indicating that the page doesn’t exist. It’s a simple structure that forms the backbone of any web application.

If you want to go further, you might want to parse query parameters from the URL. This can be essential for dynamic content generation. Node’s url module makes it easy to extract these parameters.

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

const server = http.createServer((req, res) => {
  const parsedUrl = url.parse(req.url, true);
  const queryParams = parsedUrl.query;

  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(queryParams));
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(Server running at http://localhost:${PORT}/);
});

In this example, when you hit the server with a URL that includes query parameters, like http://localhost:3000/?name=Jeff&age=30, the server will respond with a JSON object containing those parameters. This is a powerful way to make your server respond dynamically based on user input.

Next, you can dive into more advanced routing or middleware concepts, but for now, understanding these basics very important for building more complex applications in Node.js. The flexibility of the native HTTP module allows you to create lightweight applications without needing heavy frameworks. Just remember that as your application grows, you might want to consider using frameworks like Express.js for better structure and routing capabilities.

Parsing query parameters like a pro

Parsing query parameters can quickly get unwieldy if you try to handle it manually, especially when dealing with complex URLs or arrays. Instead of just relying on the deprecated url.parse() method, modern Node.js encourages using the WHATWG URL API, which is more robust and easier to work with.

Here’s how you can leverage the URL class to parse query parameters elegantly:

const http = require('http');

const server = http.createServer((req, res) => {
  const baseURL = http://${req.headers.host};
  const myURL = new URL(req.url, baseURL);

  const params = myURL.searchParams;
  const response = {};

  // Iterate over all query parameters
  for (const [key, value] of params.entries()) {
    // Handle multiple values for same key
    if (response[key]) {
      if (Array.isArray(response[key])) {
        response[key].push(value);
      } else {
        response[key] = [response[key], value];
      }
    } else {
      response[key] = value;
    }
  }

  res.statusCode = 200;
  res.setHeader('Content-Type', 'application/json');
  res.end(JSON.stringify(response));
});

const PORT = 3000;
server.listen(PORT, () => {
  console.log(Server running at http://localhost:${PORT}/);
});

Notice how myURL.searchParams is a URLSearchParams object, making iteration simpler. It natively supports multiple values for the same key, which makes dealing with inputs like ?tag=javascript&tag=nodejs easier.

If you want to check for the existence of a parameter or retrieve its value safely, URLSearchParams has useful methods like has() and get():

if (params.has('user')) {
  const user = params.get('user');
  // Use the user parameter safely here
}

When building APIs, keep in mind that query parameters come in as strings. If you expect numbers or booleans, you’ll have to parse and validate them explicitly:

const limitParam = params.get('limit');
const limit = limitParam ? parseInt(limitParam, 10) : 10;

if (isNaN(limit) || limit < 1) {
  res.statusCode = 400;
  res.end(JSON.stringify({ error: 'Invalid limit specified' }));
  return;
}

This level of validation can save you from subtle bugs or injection attacks down the road. Query strings are untrusted input, and treating them carefully is a core part of writing resilient server code.

For complex parameter parsing beyond the basics, you might eventually pull in query parsing libraries like qs which support nested structures and richer data types. But for simpler use cases, Node’s built-in URL and URLSearchParams usually have you covered with a clean API surface and great performance.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *