nuxt logo

Tradução da Documentação (Não Oficial)

servidor

O diretório server/ é usado para registrar manipuladores de API e servidor em sua aplicação.

O Nuxt escaneia automaticamente os arquivos dentro desses diretórios para registrar manipuladores de API e servidor com suporte a Hot Module Replacement (HMR).

Estrutura do diretório
-| server/
---| api/
-----| hello.ts      # /api/hello
---| routes/
-----| bonjour.ts    # /bonjour
---| middleware/
-----| log.ts        # log de todas as requisições

Cada arquivo deve exportar uma função padrão definida com defineEventHandler() ou eventHandler() (alias).

O manipulador pode retornar diretamente dados JSON, uma Promise, ou usar event.node.res.end() para enviar uma resposta.

server/api/hello.ts
export default defineEventHandler((event) => {
  return {
    hello: 'world'
  }
})

Agora você pode chamar essa API universalmente em suas páginas e componentes:

pages/index.vue
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>

<template>
  <pre>{{ data }}</pre>
</template>

Rotas do Servidor

Arquivos dentro de ~/server/api são automaticamente prefixados com /api em sua rota.

Para adicionar rotas de servidor sem o prefixo /api, coloque-as no diretório ~/server/routes.

Exemplo:

server/routes/hello.ts
export default defineEventHandler(() => 'Hello World!')

Dado o exemplo acima, a rota /hello estará acessível em http://localhost:3000/hello.

Observe que atualmente as rotas do servidor não suportam a funcionalidade completa de rotas dinâmicas como as páginas.

Middleware do Servidor

O Nuxt lerá automaticamente qualquer arquivo em ~/server/middleware para criar middleware de servidor para seu projeto.

Os manipuladores de middleware serão executados em todas as requisições antes de qualquer outra rota do servidor para adicionar ou verificar cabeçalhos, registrar requisições ou estender o objeto de requisição do evento.

Os manipuladores de middleware não devem retornar nada (nem fechar ou responder à requisição) e apenas inspecionar ou estender o contexto da requisição ou lançar um erro.

Exemplos:

server/middleware/log.ts
export default defineEventHandler((event) => {
  console.log('Nova requisição: ' + getRequestURL(event))
})
server/middleware/auth.ts
export default defineEventHandler((event) => {
  event.context.auth = { user: 123 }
})

Plugins do Servidor

O Nuxt lerá automaticamente qualquer arquivo no diretório ~/server/plugins e os registrará como plugins Nitro. Isso permite estender o comportamento em tempo de execução do Nitro e conectar-se a eventos do ciclo de vida.

Exemplo:

server/plugins/nitroPlugin.ts
export default defineNitroPlugin((nitroApp) => {
  console.log('Plugin Nitro', nitroApp)
})
Veja também Plugins Nitro

Utilitários do Servidor

As rotas do servidor são alimentadas por h3js/h3, que vem com um conjunto útil de auxiliares.

Veja também Auxiliares de Requisição H3 Disponíveis

Você pode adicionar mais auxiliares dentro do diretório ~/server/utils.

Por exemplo, você pode definir um utilitário de manipulador personalizado que envolve o manipulador original e realiza operações adicionais antes de retornar a resposta final.

Exemplo:

server/utils/handler.ts
import type { EventHandler, EventHandlerRequest } from 'h3'

export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> (
  handler: EventHandler<T, D>
): EventHandler<T, D> =>
  defineEventHandler<T>(async event => {
    try {
      // faça algo antes do manipulador de rota
      const response = await handler(event)
      // faça algo após o manipulador de rota
      return { response }
    } catch (err) {
      // Tratamento de erro
      return { err }
    }
  })

Tipos do Servidor

Este recurso está disponível a partir do Nuxt >= 3.5

Para melhorar a clareza dentro do seu IDE entre as importações automáticas de 'nitro' e 'vue', você pode adicionar um ~/server/tsconfig.json com o seguinte conteúdo:

server/tsconfig.json
{
  "extends": "../.nuxt/tsconfig.server.json"
}

Atualmente, esses valores não serão respeitados ao verificar tipos (nuxt typecheck), mas você deve obter melhores dicas de tipo no seu IDE.

Receitas

Parâmetros de Rota

As rotas do servidor podem usar parâmetros dinâmicos dentro de colchetes no nome do arquivo, como /api/hello/[name].ts, e serem acessadas via event.context.params.

server/api/hello/[name\
export default defineEventHandler((event) => {
  const name = getRouterParam(event, 'name')

  return `Hello, ${name}!`
})

Alternativamente, use getValidatedRouterParams com um validador de esquema como Zod para segurança em tempo de execução e tipo.

Agora você pode chamar essa API universalmente em /api/hello/nuxt e obter Hello, nuxt!.

Correspondência de Método HTTP

Os nomes dos arquivos de manipulador podem ser sufixados com .get, .post, .put, .delete, ... para corresponder ao Método HTTP da requisição.

server/api/test.get.ts
export default defineEventHandler(() => 'Manipulador de teste GET')
server/api/test.post.ts
export default defineEventHandler(() => 'Manipulador de teste POST')

Dado o exemplo acima, ao buscar /test com:

  • Método GET: Retorna Manipulador de teste GET
  • Método POST: Retorna Manipulador de teste POST
  • Qualquer outro método: Retorna erro 405

Você também pode usar index.[method].ts dentro de um diretório para estruturar seu código de forma diferente, isso é útil para criar namespaces de API.

export default defineEventHandler((event) => {
  // manipular requisições GET para o endpoint `api/foo`
})

Rota Catch-all

Rotas catch-all são úteis para manipulação de rotas de fallback.

Por exemplo, criar um arquivo chamado ~/server/api/foo/[...].ts registrará uma rota catch-all para todas as requisições que não correspondem a nenhum manipulador de rota, como /api/foo/bar/baz.

server/api/foo/[...\
export default defineEventHandler((event) => {
  // event.context.path para obter o caminho da rota: '/api/foo/bar/baz'
  // event.context.params._ para obter o segmento da rota: 'bar/baz'
  return `Manipulador padrão foo`
})

Você pode definir um nome para a rota catch-all usando ~/server/api/foo/[...slug].ts e acessá-lo via event.context.params.slug.

server/api/foo/[...slug\
export default defineEventHandler((event) => {
  // event.context.params.slug para obter o segmento da rota: 'bar/baz'
  return `Manipulador padrão foo`
})

Manipulação de Corpo

server/api/submit.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  return { body }
})

Alternativamente, use readValidatedBody com um validador de esquema como Zod para segurança em tempo de execução e tipo.

Agora você pode chamar essa API universalmente usando:

app.vue
async function submit() {
  const { body } = await $fetch('/api/submit', {
    method: 'post',
    body: { test: 123 }
  })
}

Estamos usando submit.post.ts no nome do arquivo apenas para corresponder a requisições com método POST que podem aceitar o corpo da requisição. Ao usar readBody dentro de uma requisição GET, readBody lançará um erro HTTP 405 Method Not Allowed.

Parâmetros de Consulta

Consulta de exemplo /api/query?foo=bar&baz=qux

server/api/query.get.ts
export default defineEventHandler((event) => {
  const query = getQuery(event)

  return { a: query.foo, b: query.baz }
})

Alternativamente, use getValidatedQuery com um validador de esquema como Zod para segurança em tempo de execução e tipo.

Tratamento de Erros

Se nenhum erro for lançado, um código de status 200 OK será retornado.

Qualquer erro não capturado retornará um erro HTTP 500 Internal Server Error.

Para retornar outros códigos de erro, lance uma exceção com createError:

server/api/validation/[id\
export default defineEventHandler((event) => {
  const id = parseInt(event.context.params.id) as number

  if (!Number.isInteger(id)) {
    throw createError({
      statusCode: 400,
      statusMessage: 'ID deve ser um inteiro',
    })
  }
  return 'Tudo certo'
})

Códigos de Status

Para retornar outros códigos de status, use o utilitário setResponseStatus.

Por exemplo, para retornar 202 Accepted

server/api/validation/[id\
export default defineEventHandler((event) => {
  setResponseStatus(event, 202)
})

Configuração em Tempo de Execução

export default defineEventHandler(async (event) => {
  const config = useRuntimeConfig(event)

  const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', {
    headers: {
      Authorization: `token ${config.githubToken}`
    }
  })

  return repo
})

Passar o event como argumento para useRuntimeConfig é opcional, mas é recomendado passá-lo para obter a configuração em tempo de execução sobrescrita por variáveis de ambiente em tempo de execução para rotas do servidor.

Cookies de Requisição

server/api/cookies.ts
export default defineEventHandler((event) => {
  const cookies = parseCookies(event)

  return { cookies }
})

Encaminhamento de Contexto e Cabeçalhos

Por padrão, nem os cabeçalhos da requisição recebida nem o contexto da requisição são encaminhados ao fazer requisições fetch em rotas do servidor. Você pode usar event.$fetch para encaminhar o contexto da requisição e cabeçalhos ao fazer requisições fetch em rotas do servidor.

server/api/forward.ts
export default defineEventHandler((event) => {
  return event.$fetch('/api/forwarded')
})

Cabeçalhos que não devem ser encaminhados não serão incluídos na requisição. Esses cabeçalhos incluem, por exemplo: transfer-encoding, connection, keep-alive, upgrade, expect, host, accept

Aguardando Promises Após a Resposta

Ao lidar com requisições de servidor, você pode precisar realizar tarefas assíncronas que não devem bloquear a resposta ao cliente (por exemplo, cache e registro). Você pode usar event.waitUntil para aguardar uma promise em segundo plano sem atrasar a resposta.

O método event.waitUntil aceita uma promise que será aguardada antes que o manipulador termine, garantindo que a tarefa seja concluída mesmo que o servidor, de outra forma, encerrasse o manipulador logo após a resposta ser enviada. Isso se integra com provedores de tempo de execução para aproveitar suas capacidades nativas para lidar com operações assíncronas após a resposta ser enviada.

server/api/background-task.ts
const timeConsumingBackgroundTask = async () => {
  await new Promise((resolve) => setTimeout(resolve, 1000))
};

export default eventHandler((event) => {
  // agendar uma tarefa em segundo plano sem bloquear a resposta
  event.waitUntil(timeConsumingBackgroundTask())

  // enviar imediatamente a resposta ao cliente
  return 'feito'
});

Uso Avançado

Configuração do Nitro

Você pode usar a chave nitro em nuxt.config para definir diretamente a configuração do Nitro.

Esta é uma opção avançada. Configurações personalizadas podem afetar implantações de produção, pois a interface de configuração pode mudar ao longo do tempo quando o Nitro é atualizado em versões semver-minor do Nuxt.

nuxt.config.ts
export default defineNuxtConfig({
  // https://nitro.build/config
  nitro: {}
})
Veja também guide > concepts > server-engine

Roteador Aninhado

server/api/hello/[...slug\
import { createRouter, defineEventHandler, useBase } from 'h3'

const router = createRouter()

router.get('/test', defineEventHandler(() => 'Hello World'))

export default useBase('/api/hello', router.handler)

Enviando Streams

Este é um recurso experimental e está disponível em todos os ambientes.

server/api/foo.get.ts
import fs from 'node:fs'
import { sendStream } from 'h3'

export default defineEventHandler((event) => {
  return sendStream(event, fs.createReadStream('/path/to/file'))
})

Enviando Redirecionamento

server/api/foo.get.ts
export default defineEventHandler(async (event) => {
  await sendRedirect(event, '/path/redirect/to', 302)
})

Manipulador ou Middleware Legado

server/api/legacy.ts
export default fromNodeMiddleware((req, res) => {
  res.end('Manipulador legado')
})

O suporte legado é possível usando h3js/h3, mas é aconselhável evitar manipuladores legados tanto quanto possível.

server/middleware/legacy.ts
export default fromNodeMiddleware((req, res, next) => {
  console.log('Middleware legado')
  next()
})

Nunca combine o callback next() com um middleware legado que seja async ou retorne uma Promise.

Armazenamento do Servidor

O Nitro fornece uma camada de armazenamento multiplataforma. Para configurar pontos de montagem de armazenamento adicionais, você pode usar nitro.storage, ou plugins do servidor.

Exemplo de adição de um armazenamento Redis:

Usando nitro.storage:

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    storage: {
      redis: {
        driver: 'redis',
        /* opções do conector redis */
        port: 6379, // Porta do Redis
        host: "127.0.0.1", // Host do Redis
        username: "", // requer Redis >= 6
        password: "",
        db: 0, // Padrão é 0
        tls: {} // tls/ssl
      }
    }
  }
})

Então, no seu manipulador de API:

server/api/storage/test.ts
export default defineEventHandler(async (event) => {
  // Listar todas as chaves com
  const keys = await useStorage('redis').getKeys()

  // Definir uma chave com
  await useStorage('redis').setItem('foo', 'bar')

  // Remover uma chave com
  await useStorage('redis').removeItem('foo')

  return {}
})
Veja também nitro.build > guide > storage

Alternativamente, você pode criar um ponto de montagem de armazenamento usando um plugin de servidor e configuração em tempo de execução:

import redisDriver from 'unstorage/drivers/redis'

export default defineNitroPlugin(() => {
  const storage = useStorage()

  // Passe dinamicamente as credenciais da configuração em tempo de execução, ou outras fontes
  const driver = redisDriver({
      base: 'redis',
      host: useRuntimeConfig().redis.host,
      port: useRuntimeConfig().redis.port,
      /* outras opções do conector redis */
    })

  // Montar driver
  storage.mount('redis', driver)
})