Response
The instance of the response class allows you to respond to the HTTP requests. AdonisJS out of the box supports sending HTML fragments, JSON objects, streams and much more.
You can access the response object from the HTTP context instance passed to the route handler, middleware, and exception handler.
Route.get('/', (ctx) => {
  ctx.response.send('hello world')
})
Sending the response
The simplest way to send a response is to return a value from the route handler.
Route.get('/', () => {
  /** Plain string */
  return 'This is the homepage'
  /** Html fragment */
  return '<p> This is the homepage </p>'
  /** JSON response */
  return { page: 'home' }
  /** Converted to ISO string */
  return new Date()
})
Along with returning a value, you can also use the response.send method to send the response. The first argument is the response body (same as the return value). Optionally you can pass a second argument to generate and set the etag
.
You can also enable ETag generation for all responses by enabling the http.etag property inside the config/app.ts file.
response.send({ hello: 'world' })
// With etag
response.send({ hello: 'world' }, true)
Serializing response body
Following is the list of data types serialized by the response class.
- Arrays and Objects are stringified using the safe stringify function
. The method is similar to 
JSON.stringifybut removes the circular references. - The number and boolean values are converted to a string.
 - Instance of Date is converted to a string by calling the 
toISOStringmethod. - Regular expressions and error objects are converted to a string by calling the 
toStringmethod on them. - Any other data type results in an exception.
 
Content type inference
The response class automatically sets the content-type and content-length headers by inspecting the response body.
The automatic content type header is only defined when you don't set it explicitly during the request lifecycle.
- Content type is set to 
application/jsonfor arrays and objects. - It is set to 
text/htmlfor HTML fragments. - JSONP responses are sent with the 
text/javascriptcontent type. - For everything else, we set the content type to 
text/plain. 
Lazy Response
Many Node.js frameworks write the response to the outgoing stream as soon as you call the response.send method. However, AdonisJS does not do the same. Instead, we wait for the route handler and middleware calls to finish before writing the final response.
This approach ensures that the last call to response.send always wins. In most cases, this behavior doesn't impact you or your applications at all. However, it allows you to post-process the response inside a middleware.
Following is an example of converting the camelCase object keys to snake_case.
The following example is not the best way to transform response. It is just a demonstration of how post-processing a response looks like
import snakeCaseKeys from 'snakecase-keys'
Route
  .get('/', async ({ response }) => {
    response.send({ fullName: 'Harminder Virk' })
  })
  .middleware(async ({ response }, next) => {
    await next()
    /**
     * Following code is executed after the route handler.
     * Read the middleware guide to learn how it works
     */
    const existingBody = response.lazyBody[0]
    if (!existingBody || existingBody.constructor !== Object) {
      return
    }
    response.send(snakeCaseKeys(existingBody))
  })
The route handler writes the response body using the response.send method in the above example. However, the downstream middleware mutates the body and re-writes it using the response.send again.
Since the response body is lazily evaluated, AdonisJS will always set the content-length and the content-type headers by inspecting the most recent response body.
Response status and headers
Following are the methods to work with the response headers and the response status.
header
The response.header method defines the HTTP response header. Using this method overwrites the existing header (if any).
response.header('Content-type', 'text/html')
append
The response.append method is similar to the header method. However, it appends to the existing header value (if any).
response.append('Set-cookie', 'cookie-value')
removeHeader
The response.removeHeader allows removing an existing response header.
response.removeHeader('Content-type')
getHeader
The response.getHeader method returns the value of an existing header.
const cookie = response.getHeader('Set-cookie')
safeHeader
The response.safeHeader method is similar to the header method. However, it only defines the header if it is not defined already.
response.safeHeader('Content-type', 'application/json')
status
The response.status method defines the status for the HTTP response. You can also use the descriptive methods
 to set the status and the response body together.
response.status(401)
safeStatus
Like the status method, the response.status only defines the status if it is not defined already.
response.safeStatus(401)
Streams & file downloads
AdonisJS has first-class support for piping streams and file downloads. Also, we make sure to clean up streams in case of errors properly.
stream
The response.stream method allows piping the stream to the response. This method does not set the content-type and the content-length headers, and you will have to set them manually.
const image = fs.createReadStream('./some-file.jpg')
response.stream(image)
In the case of errors, A 500 response is sent to the client. However, you can send a custom status code and message by defining a callback. The callback must return an array with the response message and the response status code.
response.stream(image, (error) => {
  return ['Unable to send file', 400]
})
download
The download method streams the file to the client by reading it from the disk. However, unlike the stream method, the download method does set the content-type and the content-length headers.
const filePath = Application.tmpPath('uploads/some-file.jpg')
response.download(filePath)
Optionally, you can also define the ETag for the file.
const filePath = Application.tmpPath('uploads/some-file.jpg')
response.download(filePath, true)
You can define a custom status code and a message by passing a callback as the third parameter.
const filePath = Application.tmpPath('uploads/some-file.jpg')
response.download(filePath, true, (error) => {
  if (error.code === 'ENOENT') {
    return ['File does not exists', 404]
  }
  return ['Cannot download file', 400]
})
attachment
The response.attachment is similar to the download method. However, it allows customizing the downloaded file name and defines the Content-Disposition
 header.
const filePath = Application.tmpPath('uploads/some-file.jpg')
response.attachment(filePath)
// define custom name
response.attachment(filePath, 'foo.jpg')
// define custom disposition
response.attachment(filePath, 'foo.jpg', 'inline')
Redirects
The response class exposes a rich API to work with redirects, including redirecting users to a route, redirecting back to the previous page, and forwarding the existing query string.
You can get an instance of the Redirect class
 using the response.redirect() method.
// Redirect back
response.redirect().back()
// Redirect to a url
response.redirect().toPath('/some/url')
Custom status code
By default, a 302 status code is used. However, you can override it using the .status method.
response.redirect().status(301).toPath('/some/url')
Redirect to a route
You can also redirect the request to a named route using the .toRoute method.
response.redirect().toRoute('PostsController.show', { id: 1 })
Define/forward query string
The .withQs allows you to forward the existing query string or define a custom query string during redirect.
response
  .redirect()
  .withQs() // 👈 forwardes the existing qs
  .back()
response
  .redirect()
  .withQs({ sort: 'id' }) // 👈 custom
  .back()
withQs with params
Calling the .withQs method with custom object multiple times merges the objects together. However, you can combine it with .clearQs method to clear the existing objects. For example:
response
  .redirect()
  .withQs({ sort: 'id' })
  .clearQs()
  .withQs({ filters: { name: 'virk' } })
  .toPath('/users')
// URL: /users?filters[name]=virk
withQs without params
Calling the withQs method without any parameters will forward the existing query string to the redirected URL. If you redirect the user back to the old page, we will use the query string from the referrer header URL.
response.redirect().withQs().back() // 👈 referrer header qs is used
response.redirect().withQs().toPath('/users') // 👈 current URL qs is used
Abort and respond
The response class allows you to abort the current HTTP request using the response.abort or response.abortIf methods.
abort
The response.abort method aborts the current request by raising an AbortException
The method accepts a total of two arguments: i.e., the response body and an optional status.
if (!auth.user) {
  response.abort('Not authenticated')
  // with custom status
  response.abort('Not authenticated', 401)
}
abortIf
The response.abortIf method accepts a condition and aborts the request when the condition is true.
response.abortIf(!auth.user, 'Not authenticated', 401)
abortUnless
The response.abortUnless method is the opposite of the abortIf method.
response.abortUnless(auth.user, 'Not authenticated', 401)
Other methods and properties
Following is the list of other methods and properties available in the response class.
finished
Find if the response has been written to the outgoing stream.
if (!response.finished) {
  response.send()
}
headersSent
An alias for the Node.js res.headersSent property.
isPending
The property is the opposite of the response.finished property.
if (response.isPending) {
  response.send()
}
vary
A shortcut to define the HTTP vary header
. Calling the vary method multiple times will append to the list of existing headers.
response.vary('Origin')
// Set multiple headers
response.vary('Accept, User-Agent')
location
A shortcut to set the HTTP location header .
response.location('/dashboard')
type
A shortcut to set the HTTP content-type header .
response.type('application/json')
You can also make use of the keywords for defining the content type. For example:
response.type('json') // defines content-type=application/json
response.type('html') // defines content-type=text/html
Descriptive response methods
The response class has a bunch of descriptive methods (one of each HTTP status) to send the response body and set the status at the same time. For example:
response.badRequest({ error: 'Invalid login credentials' })
response.forbidden({ error: 'Unauthorized' })
response.created({ data: user })
Here's the list of all the available methods.
Extending Response class
You can extend the Response class using macros or getters. The best place to extend the response is inside a custom service provider.
Open the pre-existing providers/AppProvider.ts file and write the following code inside the boot method.
import { ApplicationContract } from '@ioc:Adonis/Core/Application'
export default class AppProvider {
  public static needsApplication = true
  constructor(protected app: ApplicationContract) {}
  public async boot() {
    const Response = this.app.container.use('Adonis/Core/Response')
    Response.macro('flash', function (messages) {
      this.ctx!.session.flash(messages)
      return this
    })
  }
}
In the above example, we have added the flash method to the response class. It sets the flash messages by internally calling the session.flash method.
You can use the newly added method as follows.
Route.post('users', ({ response }) => {
  response.flash({ success: 'User created' })
})
Informing TypeScript about the method
The flash property is added at the runtime, and hence TypeScript does not know about it. To inform the TypeScript, we will use declaration merging
 and add the property to the ResponseContract interface.
Create a new file at path contracts/response.ts (the filename is not important) and paste the following contents inside it.
declare module '@ioc:Adonis/Core/Response' {
  interface ResponseContract {
    flash(messages: any): this
  }
}
Additional reading
Following are some of the additional guides to learn more about the topics not covered in this document.