導入
AstroプロジェクトにgenkoのSDKを入れ、記事一覧をビルド時に、記事詳細をシェアボタン付きで表示する手順。
Astroプロジェクトに@genko-me/sdkを入れ、記事一覧と記事詳細を表示するまでの手順です。一覧・詳細はどちらもビルド時に確定させます(既定のoutput: 'static'のままで動きます)。詳細ページにはReactのShareButtonsをislandとして添えます。
ワークスペースの作成とブログAPIの用意はクイックスタートの手順1〜3にまとめています。
用意するもの
- genko.meのアカウントとワークスペース。APIの作成とAPIキーの発行にはオーナー権限が必要です。
- 記事が1件以上、保存済みかつ公開状態で入っているAPI。下書きのままでは配信APIから取得できません。
- Node.js 22.12以降。 Astroは偶数バージョンだけに対応しており、
v23のような奇数バージョンは対象外です。 - 既存のAstroプロジェクト(
npm create astro@latestで作成したもの)。
以下のyour-workspaceは自分のワークスペースIDに、blogは自分のエンドポイントに置き換えます。
インストール
npm install @genko-me/sdk記事詳細にシェアボタンも出す場合は、Reactのisland用に次も入れます。npx astro add reactでも同じ状態になりますが、対話式のプロンプトが挟まるため、ここでは手動の手順を示します。
npm install @astrojs/react react react-dom @genko-me/reactimport { defineConfig } from "astro/config";import react from "@astrojs/react";
export default defineConfig({ integrations: [react()],});@genko-me/reactはReact 19をpeerDependencyに指定していますが、必須ではありません(RichTextしか使わないページならreact自体を追加する必要もありません)。今回はShareButtonsをislandにするため、@astrojs/reactと一緒に入れています。
APIキーとワークスペースIDを設定する
APIキーは管理画面の「設定・プラン」→「APIキー」(/w/your-workspace/settings/api-keys)で発行します。「選択したAPIのみ」でblogだけを許可しておくと安全です。作成直後に表示される値は後から再表示できません。
GENKO_API_KEY=発行したキーAstroのフロントマターとページはサーバー側(ビルド時、または後述のリクエスト時)で動くコードなので、PUBLIC_を付ける必要はありません。 PUBLIC_はクライアントのJavaScriptにも埋め込みたい値だけに使うプレフィックスです。ここで付けると、APIキーが不要にブラウザへ渡ってしまいます。
接続の設定を1か所にまとめます。
import { listApi } from "@genko-me/sdk";
export type Blog = { title: string; body: string };
export const apis = { blog: listApi<Blog>({ fields: [ { id: "title", type: "text" }, { id: "body", type: "richtext" }, ], }),};import { createGenko } from "@genko-me/sdk";import { apis } from "./schema";
export const genko = createGenko({ workspace: "your-workspace", apiKey: process.env.GENKO_API_KEY!, apis,});
export const client = genko.apis;import.meta.envではなくprocess.envを使っています。理由は実践の下書きプレビューの節にまとめています——ここでの一覧・詳細はどちらもビルド時に確定するので実害はありませんが、最初から同じ書き方にしておけば、あとでページの一部だけをリクエスト時レンダリングに切り替えても書き直さずに済みます。
記事一覧を出す
---import { client } from "../../lib/genko";
const { contents, totalCount } = await client.blog.list({ limit: 6, orders: "-publishedAt" });---<html lang="ja"> <body> <main> <h1>ブログ(全{totalCount}件)</h1> {contents.length === 0 ? ( <p>公開されている記事はありません。</p> ) : ( <ul> {contents.map((post) => ( <li><a href={`/blog/${post.id}`}>{post.title}</a></li> ))} </ul> )} </main> </body></html>npm run devで/blogを開き、一覧が表示されることを確認します。フロントマターのawaitはビルド時(astro build)にも実行され、結果がそのまま静的HTMLに焼き込まれます。
記事詳細を出す
詳細は動的ルートsrc/pages/blog/[id].astroに置きます。既定のoutput: 'static'では、動的ルートはgetStaticPaths()が返したパスの分だけビルド時に生成されます。全件を洗い出すにはgetAll()を使います。
---import { client } from "../../lib/genko";import { ShareButtons } from "@genko-me/react/share-buttons";
export async function getStaticPaths() { const posts = await client.blog.getAll(); return posts.map((post) => ({ params: { id: post.id }, props: { post } }));}
const { post } = Astro.props;---<html lang="ja"> <body> <main> <h1>{post.title}</h1> <div set:html={post.body} /> <ShareButtons client:load url={`https://your-site.example/blog/${post.id}`} title={post.title} /> </main> </body></html>getStaticPaths()はpropsで渡したpostをそのままページへ渡せるので、詳細取得をget()でもう一度呼ぶ必要はありません。本文はpost.bodyに入ったHTML文字列なので、Astroのset:htmlで展開します(genko.meのリッチテキストは保存時にサーバー側でサニタイズ済みです)。
ShareButtonsは@genko-me/react/share-buttonsという別のsubpathからimportします(クリック操作を持つ部品だけがここに分かれています)。client:loadを付けた部分だけがブラウザ用のJavaScriptとして出力され、見出しと本文は引き続きJSゼロのまま届きます。
npm run buildを実行し、dist/に記事の数だけHTMLが生成されていること、npm run previewで詳細ページを開いてシェアボタンが押せることを確認します。
表示されないとき
| 状況 | 確認すること |
|---|---|
| 一覧が空 | 記事が保存済みで「公開」か。公開終了日時を過ぎていないか |
401 | APIキーが有効期間内か。.envをGitの追跡対象に入れていないか、ビルド環境にも同じ変数を設定したか |
403 | APIキーを発行したワークスペースと接続先が同じか |
| ビルドが記事を反映しない | astro buildはビルド時点の内容を焼き込みます。記事を公開・変更したら再ビルドが必要です(実践のWebhookの節) |
次は実践で、ページ送り・下書きプレビュー・コンテンツ更新の反映を組み立てます。
最終更新: 2026年9月17日