import RecipeLinks from "~/components/RecipeLinks.astro";

Astroでは、どんな種類のデータでも提供できるカスタムエンドポイントを作成できます。これを利用して、画像を生成したり、RSSを公開したり、またはAPIルーティングとして使用してサイトの完全なAPIを構築したりできます。

静的に生成されたサイトでは、カスタムエンドポイントは静的ファイルを生成するため、ビルド時に呼び出されます。SSRモードを選択した場合、カスタムエンドポイントはリクエストに応じて呼び出される動的なサーバーエンドポイントに変わります。静的エンドポイントとSSRエンドポイントは同じ様に定義されますが、SSRエンドポイントは追加機能をサポートします。

静的ファイルのエンドポイント

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

エンドポイントは、Astroグローバルと同様のプロパティを持つコンテキストオブジェクトを受け取るGET関数(asyncも可)をエクスポートします。以下のエンドポイントはnameurlを持つレスポンスオブジェクトを返しており、Astroはビルド時にこれを呼び出し、bodyの内容を使ってファイルを生成します。

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

Astro v3.0以降、返り値のResponseオブジェクトがencodingプロパティを含む必要はなくなりました。たとえば、バイナリの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型を使用してエンドポイント関数に型付けもできます。

ts
import type { APIRoute } from 'astro';export const GET: APIRoute = async ({ params, request }) => {...}

paramsと動的ルーティング

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

ts
import type { APIRoute } from 'astro';const usernames = ["Sarah", "Chris", "Yan", "Elian"]export const GET: APIRoute = ({ params, request }) => {  const id = params.id;  return new Response(    JSON.stringify({      name: usernames[id]    })  )}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エンドポイントが生成されます。エンドポイントによる動的ルーティングはページと同じように動作しますが、エンドポイントはコンポーネントではなく関数であるため、propsはサポートされていません。

request

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

ts
import type { APIRoute } from 'astro';export const GET: APIRoute = ({ params, request }) => {  return new Response(JSON.stringify({      path: new URL(request.url).pathname    })  )}

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

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

しかし、staticモードとは異なり、serverモードを設定すると、エンドポイントはリクエストされた時点でビルドされます。これにより、ビルド時には利用できない新しい機能が利用可能となり、リクエストをリッスンするAPIルートを構築したり、実行時にサーバー上で安全にコードを実行できるようになります。

<RecipeLinks slugs={["ja/recipes/call-endpoints" ]}/>

:::note これらの例を試す前に、必ずSSRを有効にしてください。 :::

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

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.idhelmetに設定されます。モックの商品データベースにhelmetが存在すれば、エンドポイントはResponseオブジェクトを作成してJSONで応答し、成功を意味するHTTPステータスコードを返します。存在しない場合は、Responseオブジェクトを使用して404で応答します。

特定のプロバイダーは、SSRモードで画像を返すためにContent-Typeヘッダーを要求します。この場合、Responseオブジェクトを使用してheadersプロパティを指定します。以下はバイナリの.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" },  });}

HTTPメソッド

GET関数に加えて、任意のHTTPメソッドの名前をもつ関数をエクスポートできます。リクエストが来た時、Astroはメソッドをチェックし、対応する関数を呼び出します。

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

ts
export const GET: APIRoute = ({ params, request }) => {  return new Response(JSON.stringify({      message: "This was a GET!"    })  )}export const POST: APIRoute = ({ request }) => {  return new Response(JSON.stringify({      message: "This was a POST!"    })  )}export const DELETE: APIRoute = ({ request }) => {  return new Response(JSON.stringify({      message: "This was a DELETE!"    })  )}export const ALL: APIRoute = ({ request }) => {  return new Response(JSON.stringify({      message: `This was a ${request.method}!`    })  )}

<RecipeLinks slugs={["ja/recipes/captcha", "ja/recipes/build-forms-api" ]}/>

request

SSRモードでは、requestプロパティは、現在のリクエストを参照する完全に使用可能なRequestオブジェクトを返します。これにより、データの取得やヘッダーのチェックができます。

ts
export const POST: APIRoute = 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 });}

リダイレクト

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

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);}