nuxt logo

ドキュメント翻訳(非公式)

server

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

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

Directory structure
-| server/
---| api/
-----| hello.ts      # /api/hello
---| routes/
-----| bonjour.ts    # /bonjour
---| middleware/
-----| log.ts        # すべてのリクエストをログ

各ファイルは 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 ルートは http://localhost:3000/hello でアクセス可能です。

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

サーバーミドルウェア

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 によって動作し、便利なヘルパーセットが付属しています。

こちらも参照 Available H3 Request Helpers

~/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 {
      // ルートハンドラの前に何かを行う
      const response = await handler(event)
      // ルートハンドラの後に何かを行う
      return { response }
    } catch (err) {
      // エラーハンドリング
      return { err }
    }
  })

サーバータイプ

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

レシピ

ルートパラメータ

サーバールートは、ファイル名にブラケットで囲まれた動的パラメータを使用し、event.context.params 経由でアクセスできます。

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

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

代わりに、Zod などのスキーマバリデータを使用して getValidatedRouterParams を使用し、ランタイムと型の安全性を確保します。

この API は /api/hello/nuxt でユニバーサルに呼び出すことができ、Hello, nuxt! を取得します。

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) => {
  // `api/foo` エンドポイントの GET リクエストを処理
})

キャッチオールルート

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

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

server/api/foo/[...\
export default defineEventHandler((event) => {
  // event.context.path でルートパスを取得: '/api/foo/bar/baz'
  // event.context.params._ でルートセグメントを取得: 'bar/baz'
  return `Default foo handler`
})

キャッチオールルートに名前を付けるには、~/server/api/foo/[...slug].ts を使用し、event.context.params.slug 経由でアクセスします。

server/api/foo/[...slug\
export default defineEventHandler((event) => {
  // event.context.params.slug でルートセグメントを取得: '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
async function submit() {
  const { body } = await $fetch('/api/submit', {
    method: 'post',
    body: { test: 123 }
  })
}

ファイル名で submit.post.ts を使用しているのは、リクエストボディを受け入れることができる POST メソッドのリクエストと一致させるためだけです。GET リクエスト内で readBody を使用すると、405 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\
export default defineEventHandler((event) => {
  const id = 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\
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
})

useRuntimeConfigevent を引数として渡すことはオプションですが、サーバールートで実行時に 環境変数 によって上書きされたランタイム設定を取得するために渡すことをお勧めします。

リクエストクッキー

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-encoding, connection, keep-alive, upgrade, expect, host, accept などが含まれます。

レスポンス後の Promise の待機

サーバーリクエストを処理する際、クライアントへのレスポンスをブロックしない非同期タスク(例えば、キャッシュやログ)を実行する必要があるかもしれません。event.waitUntil を使用して、レスポンスを遅らせることなくバックグラウンドで Promise を待機できます。

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

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

export default eventHandler((event) => {
  // レスポンスをブロックせずにバックグラウンドタスクをスケジュール
  event.waitUntil(timeConsumingBackgroundTask())

  // クライアントに即座にレスポンスを送信
  return 'done'
});

高度な使用法

Nitro 設定

nuxt.config 内で nitro キーを使用して、Nitro 設定 を直接設定できます。

これは高度なオプションです。カスタム設定は、Nitro が Nuxt の semver-minor バージョンでアップグレードされると、設定インターフェースが変更される可能性があるため、プロダクションデプロイメントに影響を与える可能性があります。

nuxt.config.ts
export default defineNuxtConfig({
  // https://nitro.build/config
  nitro: {}
})
こちらも参照 guide > concepts > server-engine

ネストされたルーター

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)

ストリームの送信

これは実験的な機能であり、すべての環境で利用可能です。

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 コネクタオプション */
        port: 6379, // Redis ポート
        host: "127.0.0.1", // Redis ホスト
        username: "", // Redis >= 6 が必要
        password: "",
        db: 0, // デフォルトは 0
        tls: {} // tls/ssl
      }
    }
  }
})

次に、API ハンドラ内で:

server/api/storage/test.ts
export default defineEventHandler(async (event) => {
  // すべてのキーをリストする
  const keys = await useStorage('redis').getKeys()

  // キーを設定する
  await useStorage('redis').setItem('foo', 'bar')

  // キーを削除する
  await useStorage('redis').removeItem('foo')

  return {}
})
こちらも参照 nitro.build > guide > storage

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

import redisDriver from 'unstorage/drivers/redis'

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

  // ランタイム設定や他のソースから動的に資格情報を渡す
  const driver = redisDriver({
      base: 'redis',
      host: useRuntimeConfig().redis.host,
      port: useRuntimeConfig().redis.port,
      /* 他の redis コネクタオプション */
    })

  // ドライバをマウント
  storage.mount('redis', driver)
})