The HttpContext object is an object that we'll be heavily working with as we develop our Adonis application. It's an object that's going to be provided to us via our middleware, route handlers, HTTP hooks, and exception handlers as we progress throughout our request's lifecycle.
It's an object that's unique to each of our application's individual requests. So, anytime a user requests a page, submits a form, submits an API request, etc we'll receive a unique HttpContext object about that user's request.
HttpContext Mutation Behavior
The way Adonis is going to pass our HttpContext object from one request lifecycle method to the other is by reference. This means that if we mutate our HttpContext object inside our middleware that mutation will remain intact when we receive that request within our route handler.
If an error were then thrown for that request in our route handler, the same mutation we made within our middleware will again be carried through to the exception handler.
By mutating our HttpContext, we can easily and effectively pass additional information, for or about a request, as that request progresses from one portion of our application to another.
HttpContext Contents
What our application's HttpContext contains actually varies depending on which packages our application has installed and registered.
For example, in this series, we've yet to cover or install the Auth module. Since we've yet to install the Auth module, we're not going to have an auth
property on our HttpContext. Once we do install and configure the Auth module within our application, however, we'll then have an auth
module on our HttpContext that'll allow us to authenticate a user, deauthenticate a user, get the currently authenticated user, and more.
Our Application's HttpContext
Let's start by understanding what our web structured Adonis application has within its HttpContext out-of-the-box.
Inspect
This is a helper method that allows us to inspect the contents of an HttpContext object.Logger
We can use the logger to output information into our terminal when working locally or our application's logs when in production.Params
This is an object containing any route parameters for the requested route. The key is the param name and the value is the URL value for the key.Request
An object containing information about the user's specific request. We can get the URL, query string info, the request body, files, etc using the request object.Response
An object that allows us to mutate how our application is going to respond to the particular request. We can set headers, cookies, etc here and define response data using this object as well.Route
An object containing information about the matched route definitionRouteKey
A unique string for the route that was requested.Session
An object that allows us to get or store information for the user's session. We can also use the session to get or set flash messages, which live only for a single request.Subdomains
An object containing all of the route's subdomain. This is only applicable if the requested route contains a subdomain definition.View
An object that allows us to render our pages within our application.
The HttpContextContract
Since Adonis uses TypeScript, our HttpContext object does have its own type, which is called the HttpContextContract.
Type Definition
In most cases, Adonis is going to be able to provide the HttpContextContract type for our HttpContext object, so we won't need to explicitly define the type. However, there are a few instances where you'll need to manually define the type for your HttpContext in order to get TypeScript support. Controllers, which we'll get into later in this series, are one of those areas.
We can easily import the type from @ioc:Adonis/Core/HttpContext
then apply the type for our HttpContext object.
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext' class ExampleController { // ctx, contains our HttpContext object public async index(ctx: HttpContextContract) { } // we can also destructure the HttpContext object public async show({ request, view }: HttpContextContract) { } }
Copied!
Extending the HttpContextContract
If we do need to extend our HttpContext object, we'll also need to extend the TypeScript interface definition for our HttpContextContract in order to get TypeScript support for our extended method or property.
declare module '@ioc:Adonis/Core/HttpContext' { interface HttpContextContract { someNewProperty: string | null } }
Copied!
This will inform TypeScript about our new method or property, preventing it from complaining that the method or property doesn't exist.
Extending the HttpContext
Just as packages can extend our application's HttpContext, we can extend our HttpContext as well. There's a couple of different ways to go about it, we're just going to be covering one for right now.
If you head into your application and view the start/routes.ts
file, you'll see a single route definition provided by Adonis for our application's welcome page. It looks like the below.
import Route from '@ioc:Adonis/Core/Route' Route.get('/', async ({ view }) => { return view.render('welcome') })
Copied!
- start
- routes.ts
Ignore everything for right now except for the callback function. This callback function is the route's handler, this is what's being passed the HttpContext object. By default, Adonis is destructuring out the view
property from the HttpContext object. Let's change this to just be ctx
for context so we have access to the full HttpContext object.
Route.get('/', async (ctx) => { return view.render('welcome') })
Copied!
- start
- routes.ts
Now that we have access to the full HttpContext object, we can extend it the same as any normal object by plopping a property or method directly on the HttpContext.
Route.get('/', async (ctx) => { ctx.test = 'testing' return view.render('welcome') })
Copied!
- start
- routes.ts
That adds the property onto our HttpContext object, however, we also need to inform TypeScript about this property and its type as well. So, let's create a new file in our contracts
directory called httpContext.ts
and extend our HttpContextContract interface with our new property.
declare module '@ioc:Adonis/Core/HttpContext' { interface HttpContextContract { test: string | null } }
Copied!
- contracts
- httpContext.ts
This extends our HttpContextContract, defined within @ioc:Adonis/Core/HttpContext
, with our test
property and defines its type as string or null.
Wrapping Up
That's all we're going to cover with the HttpContext for right now. My goal with this lesson was to get you familiar with what the HttpContext is, what it contains, how it's passed, and how we can extend it. This knowledge will help make understanding routing, route handling, and middleware a little easier going forward.
Join The Discussion! (5 Comments)
Please sign in or sign up for free to join in on the dicussion.
Anonymous (SoleWinnah843)
Nice
Please sign in or sign up for free to reply
Anonymous (BobcatRayna988)
muito bom esse conteúdo!
Please sign in or sign up for free to reply
frp
The adonis 6 docs talk about extending httpcontext through macros and getters. Does that mean we can't just add a property like you do here? Also, contracts are out now, can I just add that interface definition in my app types file? I want to put together an object of properties I need throughout a request and add it to httpcontext. I was thinking of doing it in the route stack middleware. As usual, their documentation only explains about half of what you need to know so I am confused. You explain all this shit way better than they do.
Please sign in or sign up for free to reply
tomgobich
Yeah, the approach is still relatively the same. The only change is the type's name and namespace. In v6 you can continue just plopping additional properties directly on the HttpContext object, v5 actually had macros and getters as well :)
The types namespace is now
@adonisjs/core/http
and the name isHttpContext
, so you can extend it's type like so:Where you put the types doesn't matter much, you can put it in the same file you're existing the context within if you'd like or you can create a specific
types
directory off the root of your project.Here's an example of adding an
organization
property on to the HttpContext within a middleware:Hope this helps!! :)
Please sign in or sign up for free to reply
jony254
Lesson four ✅
Please sign in or sign up for free to reply