サーバー

server/ ディレクトリは、API とサーバーハンドラをアプリケーションに登録するために使用されます。

Nuxt は、これらのディレクトリ内のファイルを自動的にスキャンして、API とサーバーハンドラをホットモジュールリプレイスメント (HMR) サポート付きで登録します。

ディレクトリ構造
-| server/
---| api/
-----| hello.ts      # /api/hello
---| routes/
-----| bonjour.ts    # /bonjour
---| middleware/
-----| log.ts        # log all requests

各ファイルは、defineEventHandler() または eventHandler() (エイリアス) で定義されたデフォルト関数をエクスポートする必要があります。

ハンドラは、JSON データ、Promise を直接返すか、event.node.res.end() を使用して応答を送信できます。

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

これで、ページやコンポーネントでこの API をユニバーサルに呼び出すことができます。

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

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

サーバー ルート

~/server/api 内のファイルは、そのルートで自動的に /api がプレフィックスとして付加されます。

/api プレフィックスなしでサーバー ルートを追加するには、~/server/routes ディレクトリに配置します。

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

上記の例では、/hello ルートは以下でアクセスできます。https://:3000/hello.

現在、サーバー ルートは、ページのように動的ルートの完全な機能をサポートしていないことに注意してください。

サーバー ミドルウェア

Nuxt は、~/server/middleware 内の任意のファイルを自動的に読み込み、プロジェクトのサーバー ミドルウェアを作成します。

ミドルウェアハンドラは、他のサーバー ルートの前にすべてのリクエストで実行され、ヘッダーの追加またはチェック、リクエストのログ記録、またはイベントのリクエストオブジェクトの拡張を行います。

ミドルウェアハンドラは何も返すべきではなく(また、リクエストを閉じたり応答したりすべきではありません)、リクエストコンテキストを検査または拡張するか、エラーをスローするだけです。

server/middleware/log.ts
export default defineEventHandler((event) => {
  console.log('New request: ' + getRequestURL(event))
})
server/middleware/auth.ts
export default defineEventHandler((event) => {
  event.context.auth = { user: 123 }
})

サーバー プラグイン

Nuxt は、~/server/plugins ディレクトリ内の任意のファイルを自動的に読み込み、Nitro プラグインとして登録します。これにより、Nitro のランタイム動作を拡張し、ライフサイクルイベントにフックすることができます。

server/plugins/nitroPlugin.ts
export default defineNitroPlugin((nitroApp) => {
  console.log('Nitro plugin', nitroApp)
})
詳細については、Nitro Plugins を参照してください。

サーバーユーティリティ

サーバー ルートは以下によって提供されます。h3js/h3便利なヘルパーのセットが付属しています。

詳細については、利用可能な H3 リクエストヘルパー を参照してください。

~/server/utils ディレクトリ内に自分でヘルパーを追加できます。

たとえば、元のハンドラをラップし、最終的な応答を返す前に追加の操作を実行するカスタムハンドラユーティリティを定義できます。

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 {
      // do something before the route handler
      const response = await handler(event)
      // do something after the route handler
      return { response }
    } catch (err) {
      // Error handling
      return { err }
    }
  })

サーバーの種類

この機能は Nuxt >= 3.5 から利用可能です。

レシピ

ルートパラメータ

サーバー ルートでは、/api/hello/[name].ts のようにファイル名に角括弧で動的パラメータを使用でき、event.context.params を介してアクセスできます。

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

  return `Hello, ${name}!`
})
または、実行時およびタイプセーフティのために Zod などのスキーマバリデーターとともに getValidatedRouterParams を使用します。

これで、/api/hello/nuxt でこの API をユニバーサルに呼び出すと、Hello, nuxt! が返されます。

HTTP メソッドの照合

ハンドラファイル名には、リクエストの HTTP メソッドと一致するように .get.post.put.delete などをサフィックスとして付けることができます。HTTP メソッド.

server/api/test.get.ts
export default defineEventHandler(() => 'Test get handler')
server/api/test.post.ts
export default defineEventHandler(() => 'Test post handler')

上記の例では、/test を以下でフェッチすると

  • GET メソッド: Test get handler を返します。
  • POST メソッド: Test post handler を返します。
  • その他のメソッド: 405 エラーを返します。

コードを異なる方法で構造化するために、ディレクトリ内で index.[method].ts を使用することもできます。これは API 名前空間を作成するのに役立ちます。

export default defineEventHandler((event) => {
  // handle GET requests for the `api/foo` endpoint
})

キャッチオールルート

キャッチオールルートは、フォールバックルート処理に役立ちます。

たとえば、~/server/api/foo/[...].ts という名前のファイルを作成すると、/api/foo/bar/baz のような、どのルートハンドラにも一致しないすべてのリクエストのキャッチオールルートが登録されます。

server/api/foo/[...].ts
export default defineEventHandler((event) => {
  // event.context.path to get the route path: '/api/foo/bar/baz'
  // event.context.params._ to get the route segment: 'bar/baz'
  return `Default foo handler`
})

~/server/api/foo/[...slug].ts を使用してキャッチオールルートに名前を設定し、event.context.params.slug を介してアクセスできます。

server/api/foo/[...slug].ts
export default defineEventHandler((event) => {
  // event.context.params.slug to get the route segment: 'bar/baz'
  return `Default foo handler`
})

ボディ処理

server/api/submit.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  return { body }
})
または、実行時およびタイプセーフティのために Zod などのスキーマバリデーターとともに readValidatedBody を使用します。

これで、この API をユニバーサルに呼び出すことができます。

app/app.vue
<script setup lang="ts">
async function submit () {
  const { body } = await $fetch('/api/submit', {
    method: 'post',
    body: { test: 123 },
  })
}
</script>
ファイル名に submit.post.ts を使用しているのは、リクエストボディを受け入れることができる POST メソッドとのリクエストに一致させるためだけです。GET リクエスト内で readBody を使用すると、readBody405 Method Not Allowed HTTP エラーをスローします。

クエリパラメータ

サンプルクエリ /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 }
})
または、実行時およびタイプセーフティのために Zod などのスキーマバリデーターとともに getValidatedQuery を使用します。

エラーハンドリング

エラーがスローされなければ、ステータスコード 200 OK が返されます。

捕捉されないエラーは、500 Internal Server Error HTTP エラーを返します。

他のエラーコードを返すには、createError を使用して例外をスローします。

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

  if (!Number.isInteger(id)) {
    throw createError({
      statusCode: 400,
      statusMessage: 'ID should be an integer',
    })
  }
  return 'All good'
})

ステータスコード

他のステータスコードを返すには、setResponseStatus ユーティリティを使用します。

たとえば、202 Accepted を返すには

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

ランタイム設定

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
})
eventuseRuntimeConfig の引数として渡すのは任意ですが、サーバー ルートでランタイム時に環境変数によって上書きされたランタイム設定を取得するためには、渡すことを推奨します。

リクエスト Cookie

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

  return { cookies }
})

コンテキストとヘッダーの転送

デフォルトでは、サーバー ルートでフェッチリクエストを行う場合、受信リクエストのヘッダーもリクエストコンテキストも転送されません。サーバー ルートでフェッチリクエストを行う際に、リクエストコンテキストとヘッダーを転送するには、event.$fetch を使用できます。

server/api/forward.ts
export default defineEventHandler((event) => {
  return event.$fetch('/api/forwarded')
})
転送すべきではないヘッダーは、リクエストに含まれません。これらのヘッダーには、例えば、transfer-encodingconnectionkeep-aliveupgradeexpecthostaccept などがあります。

レスポンス後のプロミス待機

サーバーリクエストを処理する際、クライアントへのレスポンスをブロックすべきでない非同期タスク(例:キャッシュ、ログ記録)を実行する必要がある場合があります。event.waitUntil を使用すると、レスポンスを遅延させることなく、バックグラウンドでプロミスを待機できます。

event.waitUntil メソッドは、ハンドラが終了する前に待機されるプロミスを受け入れ、サーバーがレスポンス送信直後にハンドラを終了させようとしても、タスクが完了することを保証します。これは、ランタイムプロバイダと統合されており、レスポンス送信後の非同期操作を処理するためのネイティブ機能を利用できます。

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

export default eventHandler((event) => {
  // schedule a background task without blocking the response
  event.waitUntil(timeConsumingBackgroundTask())

  // immediately send the response to the client
  return 'done'
})

高度な使用法

Nitro 設定

nuxt.config 内の nitro キーを使用して、直接Nitro 設定.

これは高度なオプションです。カスタム設定は、Nuxt のセマンティックバージョンマイナーバージョンで Nitro がアップグレードされた際に、設定インターフェースが時間の経過とともに変更される可能性があるため、本番環境のデプロイに影響を与える可能性があります。
nuxt.config.ts
export default defineNuxtConfig({
  // https://nitro.build/config
  nitro: {},
})
詳細については、ドキュメント > 4 X > ガイド > コンセプト > サーバーエンジン を参照してください。

ネストされたルーター

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

const router = createRouter()

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

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

ストリームの送信

これは実験的な機能であり、すべての環境で利用できます。
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'))
})

リダイレクトの送信

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

レガシーハンドラまたはミドルウェア

server/api/legacy.ts
export default fromNodeMiddleware((req, res) => {
  res.end('Legacy handler')
})
レガシーサポートは以下を使用して可能です。h3js/h3しかし、レガシーハンドラはできる限り避けることをお勧めします。
server/middleware/legacy.ts
export default fromNodeMiddleware((req, res, next) => {
  console.log('Legacy middleware')
  next()
})
next() コールバックと、async であるか Promise を返すレガシーミドルウェアを組み合わせないでください。

サーバー ストレージ

Nitro はクロスプラットフォームのストレージレイヤーを提供しています。追加のストレージマウントポイントを設定するには、nitro.storage、またはサーバープラグインを使用できます。

Redis ストレージを追加する例

nitro.storage の使用

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    storage: {
      redis: {
        driver: 'redis',
        /* redis connector options */
        port: 6379, // Redis port
        host: '127.0.0.1', // Redis host
        username: '', // needs Redis >= 6
        password: '',
        db: 0, // Defaults to 0
        tls: {}, // tls/ssl
      },
    },
  },
})

次に、API ハンドラで

server/api/storage/test.ts
export default defineEventHandler(async (event) => {
  // List all keys with
  const keys = await useStorage('redis').getKeys()

  // Set a key with
  await useStorage('redis').setItem('foo', 'bar')

  // Remove a key with
  await useStorage('redis').removeItem('foo')

  return {}
})
Nitro Storage Layer の詳細については、こちらをご覧ください。

または、サーバープラグインとランタイム設定を使用してストレージマウントポイントを作成することもできます。

import redisDriver from 'unstorage/drivers/redis'

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

  // Dynamically pass in credentials from runtime configuration, or other sources
  const driver = redisDriver({
    base: 'redis',
    host: useRuntimeConfig().redis.host,
    port: useRuntimeConfig().redis.port,
    /* other redis connector options */
  })

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