HTTPS methods and Restful Routing

In this chapter, we'll explore the fundamentals and advanced concepts of HTTPS methods and RESTful routing in Express.js. Express.js is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications. Understanding HTTPS methods and RESTful routing is crucial for building scalable and maintainable APIs.

Overview of HTTP and HTTPS

HTTP (HyperText Transfer Protocol) is the foundation of any data exchange on the Web. It is a protocol used for transmitting hypertext over the Internet. HTTPS (HyperText Transfer Protocol Secure) is an extension of HTTP. It is used for secure communication over a computer network, within a web browser.

HTTP Methods

HTTP defines a set of request methods to indicate the desired action to be performed for a given resource. Let’s go through each method in detail.

GET

The GET method is used to retrieve information from the server. It is the most common HTTP method.

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

app.get('/users', (req, res) => {
    res.send('GET request to the users endpoint');
});

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

				
			

Explanation:

  • We create an Express application.
  • Define a route for the GET request at the /users endpoint.
  • Send a response when this endpoint is hit.
  • Start the server on port 3000.

Output: When you navigate to http://localhost:3000/users in your browser, you will see “GET request to the users endpoint”.

POST

The POST method is used to submit data to the server. It is commonly used for creating new resources.

				
					const express = require('express');
const app = express();
app.use(express.json());

app.post('/users', (req, res) => {
    const user = req.body;
    res.send(`User ${user.name} added`);
});

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

				
			

Explanation:

  • We use express.json() middleware to parse JSON bodies.
  • Define a route for the POST request at the /users endpoint.
  • Extract user data from the request body and send a response.
  • Start the server on port 3000.

Output: Using a tool like Postman, send a POST request to http://localhost:3000/users with a JSON body { "name": "John" }. The response will be “User John added”.

PUT

The PUT method is used to update an existing resource.

				
					const express = require('express');
const app = express();
app.use(express.json());

app.put('/users/:id', (req, res) => {
    const id = req.params.id;
    const user = req.body;
    res.send(`User ${id} updated with name ${user.name}`);
});

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

				
			

Explanation:

  • We use express.json() middleware to parse JSON bodies.
  • Define a route for the PUT request at the /users/:id endpoint.
  • Extract the user ID from the URL parameters and the new user data from the request body.
  • Send a response indicating the user has been updated.
  • Start the server on port 3000.

Output: Using Postman, send a PUT request to http://localhost:3000/users/1 with a JSON body { "name": "Jane" }. The response will be “User 1 updated with name Jane”.

DELETE

The DELETE method is used to delete a resource.

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

app.delete('/users/:id', (req, res) => {
    const id = req.params.id;
    res.send(`User ${id} deleted`);
});

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

				
			

Explanation:

  • Define a route for the DELETE request at the /users/:id endpoint.
  • Extract the user ID from the URL parameters.
  • Send a response indicating the user has been deleted.
  • Start the server on port 3000.

Output: Using Postman, send a DELETE request to http://localhost:3000/users/1. The response will be “User 1 deleted”.

PATCH

The PATCH method is used to make partial updates to a resource.

				
					const express = require('express');
const app = express();
app.use(express.json());

app.patch('/users/:id', (req, res) => {
    const id = req.params.id;
    const updates = req.body;
    res.send(`User ${id} updated with ${JSON.stringify(updates)}`);
});

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

				
			

Explanation:

  • We use express.json() middleware to parse JSON bodies.
  • Define a route for the PATCH request at the /users/:id endpoint.
  • Extract the user ID from the URL parameters and the updates from the request body.
  • Send a response indicating the user has been updated.
  • Start the server on port 3000.

Output: Using Postman, send a PATCH request to http://localhost:3000/users/1 with a JSON body { "name": "John Doe" }. The response will be “User 1 updated with {“name”:”John Doe”}”.

HEAD

The HEAD method is used to retrieve the headers for a resource, similar to GET, but without the response body.

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

app.head('/users', (req, res) => {
    res.sendStatus(200);
});

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

				
			

Explanation:

  • Define a route for the HEAD request at the /users endpoint.
  • Send a status code of 200.
  • Start the server on port 3000.

Output: Using Postman, send a HEAD request to http://localhost:3000/users. The response will be an empty body with a status code of 200.

OPTIONS

The OPTIONS method is used to describe the communication options for the target resource.

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

app.options('/users', (req, res) => {
    res.set('Allow', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
    res.sendStatus(204);
});

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

				
			

Explanation:

  • Define a route for the OPTIONS request at the /users endpoint.
  • Set the Allow header to indicate the allowed methods for this endpoint.
  • Send a status code of 204 (No Content).
  • Start the server on port 3000.

Output: Using Postman, send an OPTIONS request to http://localhost:3000/users. The response will be an empty body with a status code of 204 and an Allow header listing the allowed methods.

Introduction to RESTful Routing

REST (Representational State Transfer) is an architectural style for designing networked applications. RESTful routing refers to the mapping of HTTP methods to CRUD (Create, Read, Update, Delete) operations in a consistent manner.

RESTful Principles:

  • Stateless: Each request from a client to server must contain all the information needed to understand and process the request.
  • Client-Server: Separation of concerns between client and server.
  • Uniform Interface: A consistent way of interacting with resources.
  • Resource-Based: Each entity is considered a resource and is accessible via a URI.

Example Resource: Users

  • GET /users: Retrieve all users
  • GET /users/: Retrieve a single user by ID
  • POST /users: Create a new user
  • PUT /users/: Update an existing user by ID
  • DELETE /users/{id}: Delete a user by ID

Setting Up an Express.js Application

To get started with Express.js, you need to install Node.js and npm (Node Package Manager).

Initialize a new project:

				
					mkdir restful-api
cd restful-api
npm init -y

				
			

Install Express.js:

				
					npm install express

				
			

Create the main application file:

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

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

				
			

Run the application:

				
					node app.js

				
			

Defining Routes in Express.js

Routes define the endpoints for your application and specify how to handle requests to those endpoints.

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

app.get('/', (req, res) => {
    res.send('Welcome to the Home Page');
});

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

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

				
			

Output:

  • http://localhost:3000/: “Welcome to the Home Page”
  • http://localhost:3000/about: “About Us”

Creating a RESTful API

Now, let’s build a RESTful API for a simple user management system.

Handling GET Requests

				
					const express = require('express');
const app = express();
app.use(express.json());

let users = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Jane' }
];

app.get('/users', (req, res) => {
    res.json(users);
});

app.get('/users/:id', (req, res) => {
    const user = users.find(u => u.id === parseInt(req.params.id));
    if (!user) return res.status(404).send('User not found');
    res.json(user);
});

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

				
			

Output:

  • http://localhost:3000/users: JSON array of users.
  • http://localhost:3000/users/1: JSON object for user with ID 1.

Handling POST Requests

				
					app.post('/users', (req, res) => {
    const user = {
        id: users.length + 1,
        name: req.body.name
    };
    users.push(user);
    res.status(201).json(user);
});

				
			

Output: Using Postman, send a POST request to http://localhost:3000/users with a JSON body { "name": "Alice" }. The response will be the newly created user.

Handling PUT Requests

				
					app.put('/users/:id', (req, res) => {
    const user = users.find(u => u.id === parseInt(req.params.id));
    if (!user) return res.status(404).send('User not found');
    user.name = req.body.name;
    res.json(user);
});

				
			

Output: Using Postman, send a PUT request to http://localhost:3000/users/1 with a JSON body { "name": "John Doe" }. The response will be the updated user.

Handling DELETE Requests

				
					app.delete('/users/:id', (req, res) => {
    const user = users.find(u => u.id === parseInt(req.params.id));
    if (!user) return res.status(404).send('User not found');
    const index = users.indexOf(user);
    users.splice(index, 1);
    res.json(user);
});

				
			

Output: Using Postman, send a DELETE request to http://localhost:3000/users/1. The response will be the deleted user.

Handling PATCH Requests

				
					app.patch('/users/:id', (req, res) => {
    const user = users.find(u => u.id === parseInt(req.params.id));
    if (!user) return res.status(404).send('User not found');
    if (req.body.name) user.name = req.body.name;
    res.json(user);
});

				
			

Output: Using Postman, send a PATCH request to http://localhost:3000/users/1 with a JSON body { "name": "John Smith" }. The response will be the partially updated user.

Middleware in Express.js

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. Middleware functions can perform the following tasks:

  • Execute any code.
  • Make changes to the request and response objects.
  • End the request-response cycle.
  • Call the next middleware function in the stack.
				
					const express = require('express');
const app = express();

const logger = (req, res, next) => {
    console.log(`${req.method} ${req.url}`);
    next();
};

app.use(logger);

app.get('/', (req, res) => {
    res.send('Home Page');
});

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

				
			

Output: Every time you navigate to any endpoint, the method and URL will be logged to the console.

Error Handling in Express.js

Error handling middleware functions are defined with four arguments: (err, req, res, next). These functions can be used to handle errors that occur during the processing of requests.

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

app.get('/', (req, res) => {
    throw new Error('Something went wrong!');
});

app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

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

				
			

Output: Navigating to http://localhost:3000/ will log the error stack to the console and send a 500 status with the message “Something broke!” to the client.

Securing Your Application with HTTPS

HTTPS ensures that data between your server and clients is encrypted. To set up HTTPS, you need an SSL certificate.

Example with Self-Signed Certificate:

Generate a self-signed certificate:

				
					openssl req -nodes -new -x509 -keyout server.key -out server.cert

				
			

Create an HTTPS server:

				
					const express = require('express');
const https = require('https');
const fs = require('fs');

const app = express();

app.get('/', (req, res) => {
    res.send('Hello, HTTPS!');
});

const options = {
    key: fs.readFileSync('server.key'),
    cert: fs.readFileSync('server.cert')
};

https.createServer(options, app).listen(3000, () => {
    console.log('HTTPS server is running on port 3000');
});

				
			

Output: Navigate to https://localhost:3000/ to see “Hello, HTTPS!”.

In this chapter, we covered the essentials of HTTPS methods and RESTful routing in Express.js. We explored various HTTP methods, built a RESTful API, and learned about middleware and error handling. Additionally, we discussed securing your application with HTTPS. With this comprehensive understanding, you can confidently build robust and secure APIs using Express.js. Happy coding !❤️

Table of Contents