サーバー
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() を使用して応答を送信できます。
export default defineEventHandler((event) => {
return {
hello: 'world',
}
})
これで、ページやコンポーネントでこの API をユニバーサルに呼び出すことができます。
<script setup lang="ts">
const { data } = await useFetch('/api/hello')
</script>
<template>
<pre>{{ data }}</pre>
</template>
サーバー ルート
~/server/api 内のファイルは、そのルートで自動的に /api がプレフィックスとして付加されます。
/api プレフィックスなしでサーバー ルートを追加するには、~/server/routes ディレクトリに配置します。
例
export default defineEventHandler(() => 'Hello World!')
上記の例では、/hello ルートは以下でアクセスできます。https://:3000/hello.
サーバー ミドルウェア
Nuxt は、~/server/middleware 内の任意のファイルを自動的に読み込み、プロジェクトのサーバー ミドルウェアを作成します。
ミドルウェアハンドラは、他のサーバー ルートの前にすべてのリクエストで実行され、ヘッダーの追加またはチェック、リクエストのログ記録、またはイベントのリクエストオブジェクトの拡張を行います。
例
export default defineEventHandler((event) => {
console.log('New request: ' + getRequestURL(event))
})
export default defineEventHandler((event) => {
event.context.auth = { user: 123 }
})
サーバー プラグイン
Nuxt は、~/server/plugins ディレクトリ内の任意のファイルを自動的に読み込み、Nitro プラグインとして登録します。これにより、Nitro のランタイム動作を拡張し、ライフサイクルイベントにフックすることができます。
例
export default defineNitroPlugin((nitroApp) => {
console.log('Nitro plugin', nitroApp)
})
サーバーユーティリティ
サーバー ルートは以下によって提供されます。h3js/h3便利なヘルパーのセットが付属しています。
~/server/utils ディレクトリ内に自分でヘルパーを追加できます。
たとえば、元のハンドラをラップし、最終的な応答を返す前に追加の操作を実行するカスタムハンドラユーティリティを定義できます。
例
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 }
}
})
サーバーの種類
レシピ
ルートパラメータ
サーバー ルートでは、/api/hello/[name].ts のようにファイル名に角括弧で動的パラメータを使用でき、event.context.params を介してアクセスできます。
export default defineEventHandler((event) => {
const name = getRouterParam(event, 'name')
return `Hello, ${name}!`
})
これで、/api/hello/nuxt でこの API をユニバーサルに呼び出すと、Hello, nuxt! が返されます。
HTTP メソッドの照合
ハンドラファイル名には、リクエストの HTTP メソッドと一致するように .get、.post、.put、.delete などをサフィックスとして付けることができます。HTTP メソッド.
export default defineEventHandler(() => 'Test get handler')
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
})
export default defineEventHandler((event) => {
// handle POST requests for the `api/foo` endpoint
})
export default defineEventHandler((event) => {
// handle GET requests for the `api/foo/bar` endpoint
})
キャッチオールルート
キャッチオールルートは、フォールバックルート処理に役立ちます。
たとえば、~/server/api/foo/[...].ts という名前のファイルを作成すると、/api/foo/bar/baz のような、どのルートハンドラにも一致しないすべてのリクエストのキャッチオールルートが登録されます。
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 を介してアクセスできます。
export default defineEventHandler((event) => {
// event.context.params.slug to get the route segment: 'bar/baz'
return `Default foo handler`
})
ボディ処理
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return { body }
})
これで、この API をユニバーサルに呼び出すことができます。
<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 を使用すると、readBody は 405 Method Not Allowed HTTP エラーをスローします。クエリパラメータ
サンプルクエリ /api/query?foo=bar&baz=qux
export default defineEventHandler((event) => {
const query = getQuery(event)
return { a: query.foo, b: query.baz }
})
エラーハンドリング
エラーがスローされなければ、ステータスコード 200 OK が返されます。
捕捉されないエラーは、500 Internal Server Error HTTP エラーを返します。
他のエラーコードを返すには、createError を使用して例外をスローします。
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 を返すには
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
})
export default defineNuxtConfig({
runtimeConfig: {
githubToken: '',
},
})
NUXT_GITHUB_TOKEN='<my-super-token>'
リクエスト Cookie
export default defineEventHandler((event) => {
const cookies = parseCookies(event)
return { cookies }
})
コンテキストとヘッダーの転送
デフォルトでは、サーバー ルートでフェッチリクエストを行う場合、受信リクエストのヘッダーもリクエストコンテキストも転送されません。サーバー ルートでフェッチリクエストを行う際に、リクエストコンテキストとヘッダーを転送するには、event.$fetch を使用できます。
export default defineEventHandler((event) => {
return event.$fetch('/api/forwarded')
})
transfer-encoding、connection、keep-alive、upgrade、expect、host、accept などがあります。レスポンス後のプロミス待機
サーバーリクエストを処理する際、クライアントへのレスポンスをブロックすべきでない非同期タスク(例:キャッシュ、ログ記録)を実行する必要がある場合があります。event.waitUntil を使用すると、レスポンスを遅延させることなく、バックグラウンドでプロミスを待機できます。
event.waitUntil メソッドは、ハンドラが終了する前に待機されるプロミスを受け入れ、サーバーがレスポンス送信直後にハンドラを終了させようとしても、タスクが完了することを保証します。これは、ランタイムプロバイダと統合されており、レスポンス送信後の非同期操作を処理するためのネイティブ機能を利用できます。
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 設定.
export default defineNuxtConfig({
// https://nitro.build/config
nitro: {},
})
ネストされたルーター
import { createRouter, defineEventHandler, useBase } from 'h3'
const router = createRouter()
router.get('/test', defineEventHandler(() => 'Hello World'))
export default useBase('/api/hello', router.handler)
ストリームの送信
import fs from 'node:fs'
import { sendStream } from 'h3'
export default defineEventHandler((event) => {
return sendStream(event, fs.createReadStream('/path/to/file'))
})
リダイレクトの送信
export default defineEventHandler(async (event) => {
await sendRedirect(event, '/path/redirect/to', 302)
})
レガシーハンドラまたはミドルウェア
export default fromNodeMiddleware((req, res) => {
res.end('Legacy handler')
})
export default fromNodeMiddleware((req, res, next) => {
console.log('Legacy middleware')
next()
})
next() コールバックと、async であるか Promise を返すレガシーミドルウェアを組み合わせないでください。サーバー ストレージ
Nitro はクロスプラットフォームのストレージレイヤーを提供しています。追加のストレージマウントポイントを設定するには、nitro.storage、またはサーバープラグインを使用できます。
Redis ストレージを追加する例
nitro.storage の使用
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 ハンドラで
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 {}
})
または、サーバープラグインとランタイム設定を使用してストレージマウントポイントを作成することもできます。
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)
})
export default defineNuxtConfig({
runtimeConfig: {
redis: { // Default values
host: '',
port: 0,
/* other redis connector options */
},
},
})