Request

Request

An instance of the request class holds data for the ongoing HTTP request, including the request body, reference to uploaded files, cookies, request headers, and much more. The request instance can be accessed using the ctx.request property.

Query string and route params

The request.qs method returns the parsed query string as an object.

import router from '@adonisjs/core/services/router'
router.get('posts', async ({ request }) => {
/*
* URL: /?sort_by=id&direction=desc
* qs: { sort_by: 'id', direction: 'desc' }
*/
request.qs()
})

The request.params method returns an object of Route params.

import router from '@adonisjs/core/services/router'
router.get('posts/:slug/comments/:id', async ({ request }) => {
/*
* URL: /posts/hello-world/comments/2
* params: { slug: 'hello-world', id: '2' }
*/
request.params()
})

You can access a single parameter using the request.param method.

import router from '@adonisjs/core/services/router'
router.get('posts/:slug/comments/:id', async ({ request }) => {
const slug = request.param('slug')
const commentId = request.param('id')
})

Request body

AdonisJS parses the request body using the bodyparser middleware registered inside the start/kernel.ts file.

You can access the request body using the request.body() method. It returns the parsed request body as an object.

import router from '@adonisjs/core/services/router'
router.post('/', async ({ request }) => {
console.log(request.body())
})

The request.all method returns a merged copy of both the request body and the query string.

import router from '@adonisjs/core/services/router'
router.post('/', async ({ request }) => {
console.log(request.all())
})

Cherry-picking values

The request.input, request.only, and the request.except methods can cherry-pick specific properties from the request data. All the cherry-picking methods lookup for values inside both the request body and the query string.

The request.only method returns an object with only the mentioned properties.

import router from '@adonisjs/core/services/router'
router.post('login', async ({ request }) => {
const credentials = request.only(['email', 'password'])
console.log(credentials)
})

The request.except method returns an object excluding the mentioned properties.

import router from '@adonisjs/core/services/router'
router.post('register', async ({ request }) => {
const userDetails = request.except(['password_confirmation'])
console.log(userDetails)
})

The request.input method returns the value for a specific property. Optionally, you can pass a default value as the second argument. The default value is returned when the actual value is missing.

import router from '@adonisjs/core/services/router'
router.post('comments', async ({ request }) => {
const email = request.input('email')
const commentBody = request.input('body')
})

Type-safe request body

The request.all, request.body, or the cherry-picking methods are not type-safe because there is no direct way for AdonisJS to know the expected data types of the request body.

However, you may use the validator to validate the request body and have static type-safety.

Request URL

The request.url method returns the request URL relative to the hostname. By default, the return value does not include the query string. However, you can get the URL with query string by calling request.url(true).

import router from '@adonisjs/core/services/router'
router.get('/users', async ({ request }) => {
/*
* URL: /users?page=1&limit=20
* url: /users
*/
request.url()
/*
* URL: /users?page=1&limit=20
* url: /users?page=1&limit=20
*/
request.url(true) // returns query string
})

The request.completeUrl method returns the complete URL, including the hostname. Again, unless explicitly told, the return value does not include the query string.

import router from '@adonisjs/core/services/router'
router.get('/users', async ({ request }) => {
request.completeUrl()
request.completeUrl(true) // returns query string
})

Request headers

The request.headers method returns the request headers as an object.

import router from '@adonisjs/core/services/router'
router.get('/', async ({ request }) => {
console.log(request.headers())
})

You can access the value for an individual header using the request.header method.

import router from '@adonisjs/core/services/router'
router.get('/', async ({ request }) => {
request.header('x-request-id')
// Header name is not case sensitive
request.header('X-REQUEST-ID')
})

Request method

The request.method method returns the HTTP method for the current request. This method returns the spoofed method when form method spoofing is enabled, and you can use the request.intended method to get the original request method.

import router from '@adonisjs/core/services/router'
router.patch('posts', async ({ request }) => {
/**
* The method that was used for route matching
*/
console.log(request.method())
/**
* The actual request method
*/
console.log(request.intended())
})

User IP Address

The request.ip method returns the user IP address for the current HTTP request. This method relies on the X-Forwarded-For header set by proxy servers like Nginx or Caddy.

Read the trusted proxies section to configure the proxies your application should trust.

import router from '@adonisjs/core/services/router'
router.get('/', async ({ request }) => {
console.log(request.ip())
})

The request.ips method returns an array of all the IP addresses set by intermediate proxies. The array is sorted by most trusted to least trusted IP address.

import router from '@adonisjs/core/services/router'
router.get('/', async ({ request }) => {
console.log(request.ips())
})

Defining a custom getIp method

If the trusted proxy settings are insufficient to determine the correct IP address, you can implement your custom getIp method.

The method is defined inside the config/app.ts file under the http settings object.

http: {
getIp(request) {
const ip = request.header('X-Real-Ip')
if (ip) {
return ip
}
return request.ips()[0]
}
}

Content negotiation

AdonisJS provides several methods for content-negotiation by parsing all the commonly supported Accept headers. For example, you can use the request.types method to get a list of all the content types accepted by a given request.

The return value of the request.types method is ordered by the client's preference (most preferred first).

import router from '@adonisjs/core/services/router'
router.get('/', async ({ request }) => {
console.log(request.types())
})

Following is the complete list of content negotiation methods.

MethodHTTP header in use
typesAccept
languagesAccept-language
encodingsAccept-encoding
charsetsAccept-charset

Sometimes you want to find the preferred content type based on what the server can support.

For the same, you can use the request.accepts method. The method takes an array of supported content types and returns the most preferred one after inspecting the Accept header. A null value is returned when unable to find a match.

import router from '@adonisjs/core/services/router'
router.get('posts', async ({ request, view }) => {
const posts = [
{
title: 'Adonis 101',
},
]
const bestMatch = request.accepts(['html', 'json'])
switch (bestMatch) {
case 'html':
return view.render('posts/index', { posts })
case 'json':
return posts
default:
return view.render('posts/index', { posts })
}
})

Similar to request.accept, the following methods can be used to find the preferred value for other Accept headers.

// Preferred language
const language = request.language(['fr', 'de'])
// Preferred encoding
const encoding = request.encoding(['gzip', 'br'])
// Preferred charset
const charset = request.charset(['utf-8', 'hex', 'ascii'])

Generating request ids

Request ids help you debug and trace application issues from logs by assigning a unique id to every HTTP request. By default, request id creation is disabled. However, you can enable it inside the config/app.ts file.

Request ids are generated using the cuid2 package. Before generating an id, we check for the X-Request-Id request header and use its value (if it exists).

config/app.ts
{
http: {
generateRequestId: true
}
}

Once enabled, you can access the id using the request.id method.

router.get('/', ({ request }) => {
// ckk9oliws0000qt3x9vr5dkx7
console.log(request.id())
})

The same request-id is also added to all the logs generated using the ctx.logger instance.

router.get('/', ({ logger }) => {
// { msg: 'hello world', request_id: 'ckk9oliws0000qt3x9vr5dkx7' }
logger.info('hello world')
})

Configuring trusted proxies

Most Node.js applications are deployed behind a proxy server like Nginx or Caddy. Therefore we have to rely on HTTP headers such as X-Forwarded-Host, X-Forwarded-For, and X-Forwarded-Proto to know about the real end-client making an HTTP request.

These headers are only used when your AdonisJS application can trust the source IP address.

You can configure which IP addresses to trust within the config/app.ts file using the http.trustProxy configuration option.

import proxyAddr from 'proxy-addr'
{
http: {
trustProxy: proxyAddr.compile(['127.0.0.1/8', '::1/128'])
}
}

The value for trustProxy can also be a function. The method should return true if the IP address is trusted; otherwise, return false.

{
http: {
trustProxy: (address) => {
return address === '127.0.0.1' || address === '123.123.123.123'
}
}
}

If you are running Nginx on the same server as your application code, you need to trust the loopback IP addresses, i.e. (127.0.0.1).

import proxyAddr from 'proxy-addr'
{
http: {
trustProxy: proxyAddr.compile('loopback')
}
}

Suppose your application is only accessible through a load balancer, and you do not have a list of IP addresses for that load balancer. Then, you can trust the proxy server by defining a callback that always returns true.

{
http: {
trustProxy: () => true
}
}

Configuring query string parser

Query strings from the request URL are parsed using the qs module. You can configure the parser settings inside the config/app.ts file.

View the list of all the available options.

http: {
qs: {
parse: {
},
}
}

Form method spoofing

The form method on an HTML form can only be set to GET, or POST, making it impossible to leverage restful HTTP methods.

However, AdonisJS allows you to workaround this limitation using form method spoofing. Form method spoofing is a fancy term for specifying the form method via the _method query string.

For method spoofing to work, you must set the form action to POST and enable the feature inside the config/app.ts file.

config/app.ts
export const http = defineConfig({
allowMethodSpoofing: true,
})

Once enabled, you can spoof the form method as follows.

<form method="POST" action="/articles/1?_method=PUT">
<!-- Update form -->
</form>
<form method="POST" action="/articles/1?_method=DELETE">
<!-- Delete form -->
</form>

Extending Request class

You can add custom properties to the Request class using macros or getters. Make sure to read the extending AdonisJS guide first if you are new to the concept of macros.

import { Request } from '@adonisjs/core/http'
Request.macro('property', function (this: Request) {
return value
})
Request.getter('property', function (this: Request) {
return value
})

Since the macros and getters are added at runtime, you must inform TypeScript about their types.

declare module '@adonisjs/core/http' {
export interface Request {
property: valueType
}
}