Unread Notifications

Latest Notifications

No Notifications

You're all set! Start a discussion by leaving a comment on a lesson or replying to an existing comment.

Let's Learn AdonisJS 5

Understanding the HttpContext

5 MIN READ
11 months ago

The HttpContext object contains unique information about individual requests our application receives. In this lesson, we'll cover what it is, how it's passed, and how we can mutate it.

Watch on YouTube

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 definition

  • RouteKey
    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) {

  }
}

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
  }
}

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.

// start/routes.ts

import Route from '@ioc:Adonis/Core/Route'

Route.get('/', async ({ view }) => {
  return view.render('welcome')
})

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.

// start/routes.ts

Route.get('/', async (ctx) => {
  return view.render('welcome')
})

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.

// start/routes.ts

Route.get('/', async (ctx) => {
  ctx.test = 'testing'

  return view.render('welcome')
})

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.

// contracts/httpContext.ts

declare module '@ioc:Adonis/Core/HttpContext' {
  interface HttpContextContract {
    test: string | null
  }
}

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.

Comment

  1. Anonymous (BobcatRayna988)
    Commented 10 months ago

    muito bom esse conte├║do!

  2. Anonymous (SoleWinnah843)
    Commented 11 months ago

    Nice

Prepared By

Tom Gobich

Burlington, KY

Owner of Adocasts, JavaScript developer, educator, PlayStation gamer, burrito eater.

Visit Website