コンテンツにスキップ

エンドポイント

Astroでは、任意の種類のデータを配信するためのカスタムエンドポイントを作成できます。これを使って画像を生成したり、RSSドキュメントを公開したり、APIルートとしてサイト用の本格的なAPIを構築したりできます。

静的に生成されるサイトでは、カスタムエンドポイントはビルド時に呼び出され、静的ファイルを生成します。SSRモードを有効にすると、カスタムエンドポイントはリクエストに応じて呼び出される動的なサーバーエンドポイントになります。静的エンドポイントとSSRエンドポイントの定義方法はほぼ同じですが、SSRエンドポイントではより多くの機能が利用できます。

カスタムエンドポイントを作成するには、/pagesディレクトリに.jsまたは.tsファイルを追加します。ビルドの過程で.js.tsの拡張子は取り除かれるため、ファイル名には作成したいデータの拡張子を含める必要があります。たとえば、src/pages/data.json.tsからは/data.jsonエンドポイントが生成されます。

エンドポイントは、Astroグローバルに似たプロパティをもつコンテキストオブジェクト (EN)を受け取るGET関数(任意でasync)をエクスポートします。以下の例では、nameurlを含むResponseオブジェクトを返しており、Astroはこれをビルド時に呼び出し、ボディの内容を使ってファイルを生成します。

src/pages/builtwith.json.ts
// 出力: /builtwith.json
export function GET({ params, request }) {
return new Response(
JSON.stringify({
name: "Astro",
url: "https://astro.build/",
}),
);
}

Astro v3.0以降では、返却されるResponseオブジェクトにencodingプロパティを含める必要はなくなりました。たとえばバイナリの.png画像を生成するには、次のようにします。

src/pages/astro-logo.png.ts
export async function GET({ params, request }) {
const response = await fetch(
"https://docs.astro.build/assets/full-logo-light.png",
);
return new Response(await response.arrayBuffer());
}

また、APIRoute型をsatisfies演算子とあわせて使うことで、エンドポイント関数に型安全性をもたせることもできます。

import type { APIRoute } from "astro";
export const GET = (async ({ params, request }) => { /* ... */ }) satisfies APIRoute;

なお、URLにファイル拡張子を含むエンドポイント(例: src/pages/sitemap.xml.ts)は、build.trailingSlash (EN)の設定に関わらず、末尾のスラッシュなし(例: /sitemap.xml)でのみアクセスできます。

エンドポイントは、ページと同じ動的ルーティング (EN)機能をサポートしています。ファイル名を角括弧で囲んだパラメータ名にして、getStaticPaths()関数 (EN)をエクスポートしましょう。すると、エンドポイント関数に渡されるparamsプロパティを通じて、そのパラメータにアクセスできます。

src/pages/api/[id].json.ts
import type { APIRoute } from "astro";
const usernames = ["Sarah", "Chris", "Yan", "Elian"];
export const GET = (({ params, request }) => {
const id = params.id;
return new Response(
JSON.stringify({
name: usernames[id],
}),
);
}) satisfies APIRoute;
export function getStaticPaths() {
return [
{ params: { id: "0" } },
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
];
}

これにより、ビルド時に/api/0.json/api/1.json/api/2.json/api/3.jsonという4つのJSONエンドポイントが生成されます。エンドポイントでの動的ルーティングは、ページの場合と同じように動作します。静的モードでは、getStaticPaths()を使ってエンドポイントにpropsを渡せます (EN)。ただし、オンデマンドレンダリングでは、エンドポイントはコンポーネントではなく関数であるため、propsを渡すことはできません。

すべてのエンドポイントはrequestプロパティを受け取りますが、静的モードでアクセスできるのはrequest.urlだけです。これは現在のエンドポイントの完全なURLを返し、ページにおけるAstro.request.url (EN)と同じように動作します。

src/pages/request-path.json.ts
import type { APIRoute } from "astro";
export const GET = (({ params, request }) => {
return new Response(
JSON.stringify({
path: new URL(request.url).pathname,
}),
);
}) satisfies APIRoute;

サーバーエンドポイント(APIルート)

Section titled “サーバーエンドポイント(APIルート)”

静的ファイルエンドポイントのセクションで説明した内容は、すべてSSRモードでも利用できます。ファイルは、Astroグローバルに似たプロパティをもつコンテキストオブジェクト (EN)を受け取るGET関数をエクスポートできます。

ただしstaticモードとは異なり、ルートでオンデマンドレンダリングを有効にすると、エンドポイントはリクエスト時に実行されます。これにより、ビルド時には利用できなかった新しい機能が使えるようになり、リクエストを待ち受けて、実行時にサーバー上で安全にコードを実行するAPIルートを構築できます。

serverモードでは、ルートはデフォルトでオンデマンドレンダリングされます。staticモードでは、カスタムエンドポイントごとにexport const prerender = falseを指定して、プリレンダリングを無効にする必要があります。

サーバーエンドポイントでは、getStaticPathsをエクスポートしなくてもparamsにアクセスできます。またResponseオブジェクトを返せるため、ステータスコードやヘッダーを設定できます。

src/pages/[id].json.js
import { getProduct } from "../db";
export async function GET({ params }) {
const id = params.id;
const product = await getProduct(id);
if (!product) {
return new Response(null, {
status: 404,
statusText: "Not found",
});
}
return new Response(JSON.stringify(product), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}

これは、動的ルートにマッチするすべてのリクエストに応答します。たとえば/helmet.jsonにアクセスすると、params.idにはhelmetが設定されます。モックの商品データベースにhelmetが存在する場合、エンドポイントはResponseオブジェクトを使ってJSONで応答し、成功を表すHTTPステータスコードを返します。存在しない場合は、Responseオブジェクトを使って404で応答します。

SSRモードでは、画像を返すためにContent-Typeヘッダーを必要とするプロバイダーがあります。その場合は、Responseオブジェクトでheadersプロパティを指定します。たとえばバイナリの.png画像を返すには、次のようにします。

src/pages/astro-logo.png.ts
export async function GET({ params, request }) {
const response = await fetch(
"https://docs.astro.build/assets/full-logo-light.png",
);
const buffer = Buffer.from(await response.arrayBuffer());
return new Response(buffer, {
headers: { "Content-Type": "image/png" },
});
}

GET関数に加えて、任意のHTTPメソッドの名前で関数をエクスポートできます。リクエストが届くと、Astroはそのメソッドを確認し、対応する関数を呼び出します。

また、対応する関数がエクスポートされていないメソッドすべてにマッチさせるために、ALL関数をエクスポートすることもできます。マッチするメソッドがないリクエストの場合は、サイトの404ページにリダイレクトされます。

src/pages/methods.json.ts
export const GET = (({ params, request }) => {
return new Response(
JSON.stringify({
message: "GETリクエストを受け取りました!",
}),
);
}) satisfies APIRoute;
export const POST = (({ request }) => {
return new Response(
JSON.stringify({
message: "POSTリクエストを受け取りました!",
}),
);
}) satisfies APIRoute;
export const DELETE = (({ request }) => {
return new Response(
JSON.stringify({
message: "DELETEリクエストを受け取りました!",
}),
);
}) satisfies APIRoute;
export const ALL = (({ request }) => {
return new Response(
JSON.stringify({
message: `${request.method}リクエストを受け取りました!`,
}),
);
}) satisfies APIRoute;

GET関数を定義していてHEAD関数を定義していない場合、AstroはGET関数を呼び出してレスポンスからボディを取り除くことで、HEADリクエストを自動的に処理します。

SSRモードでは、requestプロパティは現在のリクエストを表わす、すべての機能を利用可能なRequestオブジェクトを返します。これにより、データを受け取ったり、ヘッダーを確認したりできます。

src/pages/test-post.json.ts
export const POST = (async ({ request }) => {
if (request.headers.get("Content-Type") === "application/json") {
const body = await request.json();
const name = body.name;
return new Response(
JSON.stringify({
message: "あなたの名前は: " + name,
}),
{
status: 200,
},
);
}
return new Response(null, { status: 400 });
}) satisfies APIRoute;

エンドポイントのコンテキストは、Astro.redirectに似たredirect()ユーティリティをエクスポートしています。

src/pages/links/[id].js
import { getLinkUrl } from "../db";
export async function GET({ params, redirect }) {
const { id } = params;
const link = await getLinkUrl(id);
if (!link) {
return new Response(null, {
status: 404,
statusText: "Not found",
});
}
return redirect(link, 307);
}
貢献する コミュニティ スポンサー