AdonisJS is primarily a web framework to create applications that respond to HTTP requests. In this guide, we will learn how AdonisJS boots the HTTP server, handles the incoming requests, and the modules available at the HTTP layer.
The HTTP layer
The HTTP layer inside an AdonisJS application consists of the following modules. It is worth mentioning that the AdonisJS HTTP layer is built from scratch and does not use any microframework under the hood.
The router module is responsible for defining the endpoints of your application, which are known as routes. A route should define a handler responsible for handling the request. The handler can be a closure or reference to a controller.
AdonisJS creates an instance of the HttpContext class for every incoming HTTP request. The HttpContext (aka
ctx) carries the information like the request body, headers, authenticated user, etc, for a given request.
The middleware pipeline in AdonisJS is an implementation of Chain of Responsibility design pattern. You can use middleware to intercept HTTP requests and respond to them before they reach the route handler.
The global exception handler handles exceptions raised during an HTTP request at a central location. You can use the global exception handler to convert exceptions to an HTTP response or report them to an external logging service.
How AdonisJS boots the HTTP server
The HTTP server is booted once you call the
boot method on the Server class. Under the hood, this method performs the following actions.
- Create the middleware pipeline
- Compile routes
- Import and instantiate the global exception handler
In a typical AdonisJS application, the
boot method is called by the Ignitor module within the
Also, it is essential to define the routes, middleware, and the global exception handler before the
boot method is called, and AdonisJS achieves that using the
start/kernel.ts preload files.
HTTP request lifecycle
Now that we have an HTTP server listening for incoming requests. Let's see how AdonisJS handles a given HTTP request.
- Creating the HttpContext
As the first step, the server module creates an instance of the HttpContext class and passes it as a reference to the middleware, route handlers, and the global exception handler.
If you have enabled the AsyncLocalStorage, then the same instance is shared as the local storage state.
- Executing server middleware stack
Next, the middleware from the server middleware stack are executed. These middleware can intercept and respond to the request before it reaches the route handler.
Also, every HTTP request goes through the server middleware stack, even if you have not defined any router for the given endpoint. This allows server middleware to add functionality to an app without relying on the routing system.
- Finding the matching route
If a server middleware does not end the request, we look for a matching route for the
req.urlproperty. The request is aborted with a
404 - Not foundexception when no matching route exists. Otherwise, we continue with the request.
- Executing the route middleware
- Executing the route handler
As the final step, the request reaches the route handler and returns to the client with a response.
Suppose an exception is raised during any step in the process. In that case, the request will be handed over to the global exception handler, who is responsible for converting the exception to a response.
- Serializing response
Once you define the response body using the
response.sendmethod or by returning a value from the route handler, we begin the response serialization process and set the appropriate headers.
Learn more about response body serialization