Exploring Middleware: A Practical Example
Tags: cloudcomputing, middleware, infrastructureascode
Published: 2023-05-16 16:43:19


Middleware functions play a crucial role in API development by intercepting and modifying requests and responses as they flow through the application. 

In this blog, we'll dive into middleware by exploring a practical example that demonstrates how middleware can be used effectively. We'll examine a code snippet that showcases the implementation of a simple middleware function and how it is integrated into an API.

Code Example:
Let's start by examining the following code snippet ([full working example](https://github.com/nitrictech/example-apps/tree/main/middleware-demo)).

```
import { api } from "@nitric/sdk";

// Perform request validation, etc.
const validate = (ctx, next) => {
  console.log("This is your middleware function running...");
  next(ctx);
};

const helloApi = api("hello", {
  middleware: [validate],
});

helloApi.get("/hello/:name", async (ctx) => {
  const { name } = ctx.req.params;
  console.log("This is your main function running...");
  ctx.res.body = `Hello ${name}`;

  return ctx;
});
```

**Understanding the Code:**

[Nitric](https://nitric.io) is a powerful framework that provides an expressive middleware layer for building web applications and APIs. 

The code snippet above showcases the use of middleware in an API implemented using the Nitric SDK. Let's break down the different components and their roles:

1. Middleware Function:

The `validate` function serves as the middleware in this example. It takes two parameters: `ctx` (short for context) and `next`. The `ctx` object encapsulates the request and response details, while `next` is a callback function that triggers the execution of the next middleware in the chain.

Within the `validate` function, you can perform various tasks such as request validation, authentication, logging, or any other preprocessing required before reaching the main function. In this example, we log a message to the console to indicate when the middleware function is running.

2. API Initialization:

The `API` function from the Nitric SDK is used to create an instance of the API with the name "hello." It takes two arguments: the API name and an options object. In the options object, we specify an array of middleware functions, in this case containing only the `validate` middleware.

3. Route Definition:

The `helloApi.get` method is used to define an HTTP GET route for the "/hello/:name" endpoint. This route handles incoming requests and executes the provided async function when a request is made to this route.

4. Main Function:

The main function, defined as an anonymous async function, receives the `ctx` object as its parameter. It extracts the `name` parameter from the request's URL and logs a message to the console indicating that the main function is running. It then sets the response's body to a greeting message using the extracted name.

**Usage and Execution Flow:**

Now that we understand the code, let's examine how it is used and the flow of execution when a request is made to the defined route:

1. API Initialization:

When the code is executed, the API instance `helloApi` is created with the name "hello" and the `validate` middleware function.

2. Request Handling:
When a GET request is made to the "/hello/:name" endpoint, the Nitric framework intercepts the request and passes it through the middleware chain.

3. Middleware Execution:
The `validate` middleware function is executed first. In our example, it logs a message to the console. After the middleware completes its tasks, it invokes the `next` callback, indicating that the next middleware or the main function should be executed.

4. Main Function Execution:
The main function is executed after the middleware. It extracts the `name` parameter from the request's URL