Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

i18n(ja): Update endpoints.mdx #4518

Merged
merged 14 commits into from
Sep 4, 2023
215 changes: 79 additions & 136 deletions src/content/docs/ja/core-concepts/endpoints.mdx
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
---
title: エンドポイント
description: あらゆる種類のデータを提供するエンドポイントの作成方法について説明します
description: どんな種類のデータでも提供できるエンドポイントの作成方法について学びます
i18nReady: true
---
Astroでは、あらゆる種類のデータを提供するためのカスタムエンドポイントを作成できます。これを利用して、画像を生成したり、RSSを公開したり、またはAPIルーティングとして使用してサイトの完全なAPIを構築できます。
import RecipeLinks from "~/components/RecipeLinks.astro";

静的に生成されたサイトでは、カスタムエンドポイントは静的ファイルを生成するため、ビルド時に呼び出されます。[SSR](/ja/guides/server-side-rendering/)モードを選択した場合、カスタムエンドポイントはリクエストに応じて呼び出されるライブサーバーエンドポイントに変わります。静的エンドポイントとSSRエンドポイントは同じ様に定義されますが、SSRエンドポイントは追加機能をサポートします。
Astroでは、どんな種類のデータでも提供できるカスタムエンドポイントを作成できます。これを利用して、画像を生成したり、RSSを公開したり、またはAPIルーティングとして使用してサイトの完全なAPIを構築したりできます。

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


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

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

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

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

戻り値のオブジェクトは、`encoding`プロパティを持つことができます。これは、Node.jsの`fs.writeFile`メソッドで受け入れられる有効な[`BufferEncoding`](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/bdd02508ddb5eebcf701fdb8ffd6e84eabf47885/types/node/buffer.d.ts#L169)であれば何でもかまいません。たとえば、バイナリのpngイメージを生成する場合は次のようになります
Astro v3.0以降、返り値の`Response`オブジェクトが`encoding`プロパティを含む必要はなくなりました。たとえば、バイナリのpng画像を生成する場合は次のようになります

```ts title="src/pages/astro-logo.png.ts" {6}
export async function get({ params, request }) {
const response = await fetch("https://astro.build/assets/press/full-logo-light.png");
const buffer = Buffer.from(await response.arrayBuffer());
return {
body: buffer,
encoding: 'binary',
};
```ts title="src/pages/astro-logo.png.ts" {3}
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());
}
```

Expand All @@ -45,39 +43,39 @@ export async function get({ params, request }) {
```ts
import type { APIRoute } from 'astro';

export const get: APIRoute = async function get ({params, request}) {
...
export const GET: APIRoute = async ({ params, request }) => {...}
```

### `params`と動的ルーティング

エンドポイントは、ページと同じ[動的ルーティング](/ja/core-concepts/routing/#%E5%8B%95%E7%9A%84%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0)機能をサポートしています。ファイル名を括弧付きのパラメーター名とし、[`getStaticPaths()`関数](/ja/reference/api-reference/#getstaticpaths)をエクスポートしてください。そして、エンドポイント関数に渡された`params`プロパティを使用して、パラメーターにアクセスします。
エンドポイントは、ページと同じ[動的ルーティング](/ja/core-concepts/routing/#%E5%8B%95%E7%9A%84%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0)機能をサポートしています。ファイル名を角括弧付きのパラメーター名とし、[`getStaticPaths()`関数](/ja/reference/api-reference/#getstaticpaths)をエクスポートしてください。そして、エンドポイント関数に渡された`params`プロパティを使用して、パラメーターにアクセスします。


```ts title="src/pages/[id].json.ts"
```ts title="src/pages/api/[id].json.ts"
import type { APIRoute } from 'astro';

const usernames = ["Sarah", "Chris", "Dan"]
const usernames = ["Sarah", "Chris", "Yan", "Elian"]

export const get: APIRoute = ({ params, request }) => {
export const GET: APIRoute = ({ params, request }) => {
const id = params.id;
return {
body: JSON.stringify({
return new Response(
JSON.stringify({
name: usernames[id]
})
}
};
)
}

export function getStaticPaths () {
export function getStaticPaths() {
return [
{ params: { id: "0"} },
{ params: { id: "1"} },
{ params: { id: "2"} },
{ params: { id: "3"} }
]
}
```

これにより、ビルド時に`/api/1.json`、`/api/2.json`、`/api/3.json`という3つのJSONエンドポイントが生成されます。エンドポイントによる動的ルーティングはページと同じように動作しますが、エンドポイントはコンポーネントではなく関数であるため、[props](/ja/reference/api-reference/#data-passing-with-props)はサポートされていません。
これにより、ビルド時に`/api/0.json`、`/api/1.json`、`/api/2.json`、`/api/3.json`という4つのJSONエンドポイントが生成されます。エンドポイントによる動的ルーティングはページと同じように動作しますが、エンドポイントはコンポーネントではなく関数であるため、[props](/ja/reference/api-reference/#data-passing-with-props)はサポートされていません。

### `request`

Expand All @@ -86,33 +84,34 @@ export function getStaticPaths () {
```ts title="src/pages/request-path.json.ts"
import type { APIRoute } from 'astro';

export const get: APIRoute = ({ params, request }) => {
return {
body: JSON.stringify({
export const GET: APIRoute = ({ params, request }) => {
return new Response(JSON.stringify({
path: new URL(request.url).pathname
})
};
)
}
```


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

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

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

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

:::note
これらの例を試す前に、必ず[SSRを有効](/ja/guides/server-side-rendering/#プロジェクトでssrを有効にする)にしてください。
:::

サーバーエンドポイントは、`getStaticPaths`をエクスポートせず`params`にアクセスでき、[`Response`](https://developer.mozilla.org/ja/docs/Web/API/Response)オブジェクトを返せるので、ステータスコードやヘッダーを設定できます。
サーバーエンドポイントは、`getStaticPaths`のエクスポートなしで`params`にアクセスできます。また、[`Response`](https://developer.mozilla.org/ja/docs/Web/API/Response)オブジェクトを返せるので、ステータスコードやヘッダーを設定できます。


```js title="src/pages/[id].json.js"
import { getProduct } from '../db';

export async function get({ params }) {
export async function GET({ params }) {
const id = params.id;
const product = await getProduct(id);

Expand All @@ -123,67 +122,74 @@ export async function get({ params }) {
});
}

return new Response(JSON.stringify(product), {
status: 200,
headers: {
"Content-Type": "application/json"
return new Response(
JSON.stringify(product), {
status: 200,
headers: {
"Content-Type": "application/json"
}
}
});
);
}
```

これは、動的ルーティングにマッチするすべてのリクエストに応答します。たとえば、`/helmet.json`に移動した場合、`params.id`は`helmet`に設定されます。モックの商品データベースに`helmet`が存在すれば、エンドポイントは`Response`オブジェクトを作成してJSONで応答し、[HTTPステータスコード](https://developer.mozilla.org/ja/docs/Web/API/Response/status)として成功を返します。存在しない場合は、`Response`オブジェクトを使用して`404`で応答します。
これは、動的ルーティングにマッチするすべてのリクエストに応答します。たとえば、`/helmet.json`に移動した場合、`params.id`は`helmet`に設定されます。モックの商品データベースに`helmet`が存在すれば、エンドポイントは`Response`オブジェクトを作成してJSONで応答し、成功を意味する[HTTPステータスコード](https://developer.mozilla.org/ja/docs/Web/API/Response/status)を返します。存在しない場合は、`Response`オブジェクトを使用して`404`で応答します。

### HTTPメソッド
特定のプロバイダーは、SSRモードで画像を返すために`Content-Type`ヘッダーを要求します。この場合、`Response`オブジェクトを使用して`headers`プロパティを指定します。以下はバイナリの`.png`画像を返却する例です。
```ts title="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メソッド](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods)名を持つ関数をエクスポートできます。リクエストが来ると、Astroはそのメソッドをチェックして、対応する関数を呼び出します。
### HTTPメソッド

また、対応するエクスポートされた関数がないメソッドにマッチするように、`all`関数をエクスポートできます。一致するメソッドがないリクエストの場合、サイトの[404ページ](/ja/core-concepts/astro-pages/#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0404%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%9A%E3%83%BC%E3%82%B8)にリダイレクトされます
`GET`関数に加えて、任意の[HTTPメソッド](https://developer.mozilla.org/ja/docs/Web/HTTP/Methods)の名前をもつ関数をエクスポートできます。リクエストが来た時、Astroはメソッドをチェックし、対応する関数を呼び出します

:::note
JavaScriptでは`delete`は予約語なので、代わりに`del`関数をエクスポートするとdeleteメソッドにマッチします。
:::
対応するエクスポートされた関数がないHTTPメソッドにマッチする`ALL`関数をエクスポートすることもできます。対応するメソッドがないリクエストが来た場合、サイトの[404ページ](/ja/core-concepts/astro-pages/#カスタム404エラーページ)にリダイレクトされます。

```ts title="src/pages/methods.json.ts"
export const get: APIRoute = ({ params, request }) => {
return {
body: JSON.stringify({
export const GET: APIRoute = ({ params, request }) => {
return new Response(JSON.stringify({
message: "This was a GET!"
})
}
};
)
}

export const post: APIRoute = ({ request }) => {
return {
body: JSON.stringify({
export const POST: APIRoute = ({ request }) => {
return new Response(JSON.stringify({
message: "This was a POST!"
})
}
)
}

export const del: APIRoute = ({ request }) => {
return {
body: JSON.stringify({
export const DELETE: APIRoute = ({ request }) => {
return new Response(JSON.stringify({
message: "This was a DELETE!"
})
}
)
}

export const all: APIRoute = ({ request }) => {
return {
body: JSON.stringify({
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`](https://developer.mozilla.org/ja/docs/Web/API/Request)オブジェクトを返します。これにより、データの受け入れやヘッダーのチェックができます
SSRモードでは、`request`プロパティは、現在のリクエストを参照する完全に使用可能な[`Request`](https://developer.mozilla.org/ja/docs/Web/API/Request)オブジェクトを返します。これにより、データの取得やヘッダーのチェックができます

```ts title="src/pages/test-post.json.ts"
export const post: APIRoute = async ({ request }) => {
export const POST: APIRoute = async ({ request }) => {
if (request.headers.get("Content-Type") === "application/json") {
const body = await request.json();
const name = body.name;
Expand All @@ -199,12 +205,12 @@ export const post: APIRoute = async ({ request }) => {

### リダイレクト

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

```js title="src/pages/links/[id].js" {14}
import { getLinkUrl } from '../db';

export async function get({ params, redirect }) {
export async function GET({ params, redirect }) {
const { id } = params;
const link = await getLinkUrl(id);

Expand All @@ -218,66 +224,3 @@ export async function get({ params, redirect }) {
return redirect(link, 307);
}
```

### 例:CAPTCHA(キャプチャ)の検証

サーバーエンドポイントをREST APIのエンドポイントとして使用することで、機密データをクライアントに公開することなく、認証、データベースアクセス、検証などの機能を実行できます。

以下の例では、Google reCAPTCHA v3を検証するためにAPIルートを使用していますが、これはクライアントにシークレットを公開しません。

サーバー上では、recaptchaのデータを受け入れるpostメソッドを定義し、reCAPTCHAのAPIを使って検証を行います。ここで、secret値を安全に定義したり、環境変数を読み込んだりできます。

```js title="src/pages/recaptcha.js"
export async function post({ request }) {
const data = await request.json();

const recaptchaURL = 'https://www.google.com/recaptcha/api/siteverify';
const requestBody = {
secret: "YOUR_SITE_SECRET_KEY", // 環境変数にできます
response: data.recaptcha // クライアントから渡されたトークン
};

const response = await fetch(recaptchaURL, {
method: "POST",
body: JSON.stringify(requestBody)
});

const responseData = await response.json();

return new Response(JSON.stringify(responseData), { status: 200 });
}
```

そして、クライアントスクリプトから`fetch`を使ってエンドポイントにアクセスします。

```astro title="src/pages/index.astro"
<html>
<head>
<script src="https://www.google.com/recaptcha/api.js"></script>
</head>

<body>
<button class="g-recaptcha"
data-sitekey="PUBLIC_SITE_KEY"
data-callback="onSubmit"
data-action="submit">CAPTCHA認証のためクリックしてください</button>

<script is:inline>
function onSubmit(token) {
fetch("/recaptcha", {
method: "POST",
body: JSON.stringify({ recaptcha: token })
})
.then((response) => response.json())
.then((gResponse) => {
if (gResponse.success) {
// CAPTCHA認証が成功した場合
} else {
// CAPTCHA認証が失敗
}
})
}
</script>
</body>
</html>
```