Response
Uma instância da classe response é usada para responder a solicitações HTTP. O AdonisJS suporta o envio de fragmentos HTML, objetos JSON, fluxos e muito mais. A instância response pode ser acessada usando a propriedade ctx.response
.
Enviando resposta
A maneira mais simples de enviar uma resposta é retornar um valor do manipulador de rota.
import router from '@adonisjs/core/services/router'
router.get('/', async () => {
/** String simples */
return 'This is the homepage.'
/** Fragmento HTML */
return '<p> This is the homepage </p>'
/** Resposta JSON */
return { page: 'home' }
/** Convertido para string ISO */
return new Date()
})
Além de retornar um valor do manipulador de rota, você pode usar o método response.send
para definir explicitamente o corpo da resposta. No entanto, chamar o método response.send
várias vezes substituirá o corpo antigo e manterá apenas o mais recente.
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
/** String simples */
response.send('This is the homepage')
/** Fragmento HTML */
response.send('<p> This is the homepage </p>')
/** Resposta JSONe */
response.send({ page: 'home' })
/** Convertido para string ISO */
response.send(new Date())
})
Um código de status personalizado para a resposta pode ser definido usando o método response.status
.
response.status(200).send({ page: 'home' })
// Enviar resposta 201 vazia
response.status(201).send('')
Conteúdo de streaming
O método response.stream
permite canalizar um fluxo para a resposta. O método destrói internamente o fluxo após terminar.
O método response.stream
não define os cabeçalhos content-type
e content-length
; você deve defini-los explicitamente antes de transmitir o conteúdo.
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
const image = fs.createReadStream('./some-file.jpg')
response.stream(image)
})
Um código de status 500 é enviado ao cliente em caso de erro. No entanto, você pode personalizar o código de erro e a mensagem definindo um retorno de chamada como o segundo parâmetro.
const image = fs.createReadStream('./some-file.jpg')
response.stream(image, () => {
const message = 'Unable to serve file. Try again'
const status = 400
return [message, status]
})
Baixando arquivos
Recomendamos usar o método response.download
em vez do método response.stream
quando você quiser transmitir arquivos do disco. Isso ocorre porque o método download
define automaticamente os cabeçalhos content-type
e content-length
.
import app from '@adonisjs/core/services/app'
import router from '@adonisjs/core/services/router'
router.get('/uploads/:file', async ({ response, params }) => {
const filePath = app.makePath(`uploads/${params.file}`)
response.download(filePath)
})
Opcionalmente, você pode gerar uma Etag para o conteúdo do arquivo. Usar Etags ajudará o navegador a reutilizar a resposta em cache da solicitação anterior (se houver).
const filePath = app.makePath(`uploads/${params.file}`)
const generateEtag = true
response.download(filePath, generateEtag)
Semelhante ao método response.stream
, você pode enviar uma mensagem de erro personalizada e um código de status definindo um retorno de chamada como o último parâmetro.
const filePath = app.makePath(`uploads/${params.file}`)
const generateEtag = true
response.download(filePath, generateEtag, (error) => {
if (error.code === 'ENOENT') {
return ['File does not exists', 404]
}
return ['Cannot download file', 400]
})
Forçar download de arquivos
O método response.attachment
é semelhante ao método response.download
, mas força os navegadores a salvar o arquivo no computador do usuário definindo o cabeçalho Content-Disposition.
import app from '@adonisjs/core/services/app'
import router from '@adonisjs/core/services/router'
router.get('/uploads/:file', async ({ response, params }) => {
const filePath = app.makePath(`uploads/${params.file}`)
response.attachment(filePath, 'custom-filename.jpg')
})
Definindo status de resposta e cabeçalhos
Definindo status
Você pode definir o status de resposta usando o método response.status
. Chamar esse método substituirá o status de resposta existente (se houver). No entanto, você pode usar o método response.safeStatus
para definir o status somente quando ele for undefined
.
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
/**
* Define o status para 200
*/
response.safeStatus(200)
/**
* Não define o status, pois ele
* já está definido
*/
response.safeStatus(201)
})
Definindo cabeçalhos
Você pode definir os cabeçalhos de resposta usando o método response.header
. Este método substitui o valor do cabeçalho existente (se ele já existir). No entanto, você pode usar o método response.safeHeader
para definir o cabeçalho somente quando ele for undefined
.
import router from '@adonisjs/core/services/router'
router.get('/', async ({ response }) => {
/**
* Define o cabeçalho do tipo de conteúdo
*/
response.safeHeader('Content-type', 'text/html')
/**
* Não define o cabeçalho content-type, pois ele
* já está definido
*/
response.safeHeader('Content-type', 'text/html')
})
Você pode usar o método response.append
para anexar valores aos valores de cabeçalho existentes.
response.append('Set-cookie', 'cookie-value')
O método response.removeHeader
remove o cabeçalho existente.
response.removeHeader('Set-cookie')
Cabeçalho X-Request-Id
Se o cabeçalho existir na solicitação atual ou se Gerando IDs de solicitação estiver habilitado, o cabeçalho estará presente na resposta.
Redirecionamentos
O método response.redirect
retorna uma instância da classe Redirect. A classe redirect usa a API fluente para construir a URL de redirecionamento.
A maneira mais simples de executar um redirecionamento é chamar o método redirect.toPath
com o caminho de redirecionamento.
import router from '@adonisjs/core/services/router'
router.get('/posts', async ({ response }) => {
response.redirect().toPath('/articles')
})
A classe redirect também permite construir uma URL a partir de uma rota pré-registrada. O método redirect.toRoute
aceita o identificador de rota como o primeiro parâmetro e os parâmetros de rota como o segundo parâmetro.
import router from '@adonisjs/core/services/router'
router.get('/articles/:id', async () => {}).as('articles.show')
router.get('/posts/:id', async ({ response, params }) => {
response.redirect().toRoute('articles.show', { id: params.id })
})
Redirecionar de volta para a página anterior
Você pode querer redirecionar o usuário para a página anterior durante os envios de formulários em caso de erros de validação. Você pode fazer isso usando o método redirect.back
.
response.redirect().back()
Código de status de redirecionamento
O status padrão para respostas de redirecionamento é 302
; você pode alterá-lo chamando o método redirect.status
.
response.redirect().status(301).toRoute('articles.show', { id: params.id })
Redirecionar com sequência de consulta
Você pode usar o método withQs
para anexar uma sequência de consulta à URL de redirecionamento. O método aceita um objeto de um par de chave-valor e o converte em uma sequência.
response.redirect().withQs({ page: 1, limit: 20 }).toRoute('articles.index')
Para encaminhar a sequência de consulta da URL de solicitação atual, chame o método withQs
sem nenhum parâmetro.
// Encaminhar sequência de consulta de URL atual
response.redirect().withQs().toRoute('articles.index')
Ao redirecionar de volta para a página anterior, o método withQs
encaminhará a sequência de consulta da página anterior.
// Encaminhar sequência de consulta de URL atual
response.redirect().withQs().back()
Abortando solicitação com erro
Você pode usar o método response.abort
para encerrar a solicitação gerando uma exceção. O método lançará uma exceção E_HTTP_REQUEST_ABORTED
e acionará o fluxo exception handling.
router.get('posts/:id/edit', async ({ response, auth, params }) => {
const post = await Post.findByOrFail(params.id)
if (!auth.user.can('editPost', post)) {
response.abort({ message: 'Cannot edit post' })
}
// continuar com o restante da lógica
})
Por padrão, a exceção criará uma resposta HTTP com um código de status 400
. No entanto, você pode especificar um código de status personalizado como o segundo parâmetro.
response.abort({ message: 'Cannot edit post' }, 403)
Executando ações após o término da resposta
Você pode ouvir o evento quando o Node.js terminar de gravar a resposta no soquete TCP usando o método response.onFinish
. Nos bastidores, usamos o pacote on-finished, então sinta-se à vontade para consultar o arquivo README do pacote para uma explicação técnica aprofundada.
router.get('posts', ({ response }) => {
response.onFinish(() => {
// lógica de limpeza
})
})
Acessando o objeto res
do Node.js
Você pode acessar o objeto res do Node.js usando a propriedade response.response
.
router.get('posts', ({ response }) => {
console.log(response.response)
})
Serialização do corpo da resposta
O conjunto de corpos de resposta usando o método response.send
é serializado para uma string antes de ser escrito como resposta para o fluxo de mensagens de saída.
A seguir está a lista de tipos de dados suportados e suas regras de serialização.
- função stringify segura. O método é semelhante a
JSON.stringify
, mas remove as referências circulares e serializaBigInt(s)
. - Os valores numéricos e booleanos são convertidos em uma string.
- A instância da classe Date é convertida em uma string chamando o método
toISOString
. - Expressões regulares e objetos de erro são convertidos em uma string chamando o método
toString
. - Qualquer outro tipo de dado resulta em uma exceção.
Inferência de tipo de conteúdo
Após serializar a resposta, a classe de resposta infere e define automaticamente os cabeçalhos content-type
e content-length
.
A seguir está a lista de regras que seguimos para definir o cabeçalho content-type
.
- O tipo de conteúdo é definido como
application/json
para matrizes e objetos. - É definido como
text/html
para fragmentos HTML. - As respostas JSONP são enviadas com o tipo de conteúdo
text/javascript
. - O tipo de conteúdo é definido como
text/plain
para todo o resto.
Estendendo a classe Response
Você pode adicionar propriedades personalizadas à classe Response usando macros ou getters. Certifique-se de ler o guia de extensão do AdonisJS primeiro se você for novo no conceito de macros.
import { Response } from '@adonisjs/core/http'
Response.macro('property', function (this: Response) {
return value
})
Response.getter('property', function (this: Response) {
return value
})
Como as macros e getters são adicionados em tempo de execução, você deve informar o TypeScript sobre seus tipos.
declare module '@adonisjs/core/http' {
export interface Response {
property: valueType
}
}