Sessions

AdonisJs has the first-class support for sessions and comes with a variety of inbuilt drivers to easily manage and store sessions. In this guide, we learn how to configure different drivers and use them.

Setup

If session provider is not already setup, make sure to install it as defined below.

adonis install @adonisjs/session

The above command installs the provider, creates the config file automatically and shows a small set of instructions to follow to set it up.

The first step is to register the provider inside start/app.js file.

const providers = [
  '@adonisjs/session/providers/SessionProvider'
]

Also, register the middleware inside start/kernel.js file.

const globalMiddleware = [
  'Adonis/Middleware/Session'
]

Supported drivers

Below is the list of drivers supported by the session provider. You can change the current driver inside config/session.js file.

The redis driver rely on @adonisjs/redis make sure to install the provider.
Name Config key Description

Cookie

cookie

Saves the session values in encrypted form inside cookies.

File

file

Saves inside a file on a server. Should not be used if you are running Adonisjs on multiple servers and behind a load balancer.

Redis

redis

Save inside redis. Ideal for scaling horizontally.

Basic example

The session object is passed as part of HTTP context, just like request and response. Let’s see how to use sessions during the HTTP lifecycle.

Route.get('/', ({ session, response }) => {
  session.put('username', 'virk')
  response.redirect('/print')
})

Route.get('/print', ({ session }) => {
  return session.get('username')
})

Session methods

Here is the list of methods.

put(key, value)

Add a key/value pair to the session store.

session.put('username', 'virk')

get(key, [defaultValue])

Returns the value for a given or the default value.

session.get('username', 'fallbackName')

all

Get everything back as an object from the session store.

session.all()

increment(key, steps)

Increment the value for a given key. Make sure the previous value is always a number.

session.increment('counter')

// or increment by 5
session.increment('counter', 5)

decrement(key, steps)

Decrement the value for a given key. Make sure the previous value is always a number.

session.increment('counter')

// or decrement by 2
session.decrement('counter', 2)

forget(key)

Remove key/value pair from the store

session.forget('username')

pull(key, defaultValue)

Remove the value from the store and get it back.

const username = session.pull('username') // returns username
request.pull('username') // null

clear

Empty the session store

session.clear()

Flash messages

Flash messages are short-lived session values for a single request only. Mainly flash messages are used to flash form errors but can be used for any other purpose.

Taking the example of HTML forms, let’s say we want to validate the user data and redirect the request back to the form with the validation errors.

Html form
<form method="POST" action="/users">
  {{ csrfField() }}
  <input type="text" name="username" />
  <button type="submit"> Submit </button>
</form>

Now let’s register the route and validate the form data.

const { validate } = use('Validator')

Route.post('users', ({ request, session, response }) => {
  const rules = { username: 'required' }
  const validation = await validate(request.all(), rules)

  if (validation.fails()) {
    session.withErrors(validation.messages()).flashAll()
    return response.redirect('back')
  }

  return 'Validation passed'
})

Now inside the view, we can grab the flash data using view helpers.

<input type="text" name="username" value="{{ old('username', '') }}" />
{{ getErrorFor('username') }}

Methods

Below is the list of available methods

flashAll

Flash the request form data.

session.flashAll()

flashOnly

Flash only selected fields.

session.flashOnly(['username', 'email'])

flashExcept

Flash except selected fields.

session.flashExcept(['password', 'csrf_token'])

withErrors

Flash with an array of errors

session
  .withErrors([{ field: 'username', message: 'Error message' }])
  .flashAll()

flash

Flash custom object

session.flash({ notification: 'You have been redirected back' })

View helpers

When using flash messages, you can use the following view helpers to read values from the flash session store.

old(key, defaultValue)

Returns the value for a given key from the flash store.

session.flashOnly(['username'])
<input type="text" name="username" value="{{ old('username', '') }}" />

hasErrorFor(key)

Find if there is an error for a given field inside the flash store.

session
  .withErrors({ username: 'Username is required' })
  .flashAll()
@if(hasErrorFor('username'))
  // display error
@endif

getErrorFor(key)

Returns the error message for a given key

session
  .withErrors({ username: 'Username is required' })
  .flashAll()

flashMessage(key, defaultValue)

Returns the flash message for a given key

session.flash({ notification: 'Update successful!' })
@if(flashMessage('notification'))
  <span> {{ flashMessage('notification') }} </span>
@endif

Session persistence

Session values are persisted in bulk when the request ends. It keeps the request/response performant since you can mutate the session store as many times as you want and a bulk update is performed at the end.

It is achieved using the middleware layer of Adonis, check out the implementation here.

However, there is a caveat to it. In case an exception is thrown, the middleware layer breaks and session values are never committed.

AdonisJs first party packages handle this gracefully, but you should commit the session manually if you are handling exceptions of your own.

const GE = require('@adonisjs/generic-exceptions')

class MyCustomException extends GE.LogicalException {
  handle (error, { session }) {
    await session.commit()
    // handle exception
  }
}