Skip to main content
version 1.0.0

Middlewares

Introduction

Middleware provide a convenient mechanism for inspecting and filtering HTTP requests entering your application. For example, Athenna includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will throw an unauthorized error. However, if the user is authenticated, the middleware will allow the request to proceed further into the application.

Additional middleware can be written to perform a variety of tasks besides authentication. For example, a logging middleware might log all incoming requests to your application.

Defining middleware

To create a new middleware, use the make:middleware command:

node artisan make:middleware EnsureApiKeyIsValid

This command will place a new EnsureApiKeyIsValid class within your app/Http/Middlewares directory. In this middleware, we will only allow access to the route if the supplied api key input matches a specified value. Otherwise, we will throw an unauthorized exception:

import { UnauthorizedException } from '@athenna/http'

export class EnsureApiKeyIsValid {
/**
* Use the constructor to resolve any dependency of the Ioc container.
*/
constructor() {}

/**
* Handle method is executed before the request gets in your controller.
*
* @param {import('@athenna/http').HandleContextContract} ctx
* @return {any}
*/
async handle({ queries }) {
if (queries.apiKey !== 'my-api-key') {
throw new UnauthorizedException('Your api key does not match with application api key.')
}
}
}

As you can see, if the given apiKey does not match our application api key, the middleware will return an unauthorized exception to the client; otherwise, the request will be passed further into the application.

It's best to envision middleware as a series of "layers" HTTP requests must pass through before they hit your application. Each layer can examine the request and even reject it entirely.

tip

All middleware are resolved via the service container, so you can use any dependencies you need within a middlewares constructor.

Registering middleware

Global middleware

If you want a middleware to run during every HTTP request to your application, list the middleware class in the globalMiddlewares property of your app/Http/Kernel.js class.

Assigning middleware to routes

If you would like to assign middleware to specific routes, you should first assign the middleware a key in your application's app/Http/Kernel.js file. You can do that inside namedMiddlewares property, you may add your own middleware to this list and assign it a key of your choosing:

// Within app\Http\Kernel class...

get namedMiddlewares() {
return {
myMiddleware: import('App/Http/Middlewares/MyMiddleware')
}
}

Once the middleware has been defined in the HTTP kernel, you may use the middleware method to assign middleware to a route:

Route.get('/welcome', () => {
//
}).middleware('myMiddleware')

Intercept middleware

Sometimes a middleware may need to do some work before the HTTP response has been sent to the client. If you define an intercept method on your middleware, the intercept method will automatically be called before the response is sent to the client:

export class InterceptMiddleware {
/**
* Use the constructor to resolve any dependency of the Ioc container.
*/
constructor() {}

/**
* Handle method is executed before the request gets in your controller.
*
* @param {import('@athenna/http').HandleContextContract} ctx
*/
async handle() {
}

/**
* Intercept method is executed before the response has been sent.
*
* @param {import('@athenna/http').InterceptContextContract} ctx
*/
async intercept({ body }) {
body.intercepted = true

// intercept should always return the new body of the response
return body
}
}

Once you have defined a intercept middleware, you should add it to the list of routes or global middleware in the app/Http/Kernel.js file.

Terminate middleware

Sometimes a middleware may need to do some work after the HTTP response has been sent to the client. If you define a terminate method on your middleware, the terminate method will automatically be called after the response is sent to the client:

export class TerminateMiddleware {
/**
* Use the constructor to resolve any dependency of the Ioc container.
*/
constructor() {}

/**
* Handle method is executed before the request gets in your controller.
*
* @param {import('@athenna/http').HandleContextContract} ctx
*/
async handle() {
}

/**
* Terminate method is executed after the response has been sent.
*
* @param {import('@athenna/http').TerminateContextContract} ctx
*/
async terminate() {
// create and save metrics of the request
}
}

Once you have defined a terminable middleware, you should add it to the list of routes or global middleware in the app/Http/Kernel file.

info

The requests log created by Athenna when the logRequests property is true in your config/http.js file are handled by a terminable middleware! You can see the code here.