Astro と microCMS を接続して記事を取得する|astro:env で APIキーを管理し、getAllContents で全件取得
この回でやること
この連載では、このサイト cyber-blow.com を Astro と microCMS で作った過程を、実際のコードと一緒に順を追って解説します。公開までの全体の流れは、総集編にまとめています。
第1回のこの記事では、次のところまで進めます。
- Astro のプロジェクトを作る
- microCMS に記事用の API を作る
- APIキーなどの環境変数を
astro:envで読み込む microcms-js-sdkで記事を全件取得する- トップページに記事のタイトルを並べて、取得できているか確かめる
見た目はまだ何もなく、記事タイトルが箇条書きで出るだけのページです。次回以降、これを記事一覧や記事詳細に育てていきます。
この回の時点のファイル構成
.
├── .env.example # 環境変数のひな形(.env にコピーして使う)
├── astro.config.mjs # 環境変数のスキーマを定義
├── package.json
├── tsconfig.json
└── src
├── lib
│ └── microcms.ts # microCMS のクライアントと記事の取得
└── pages
└── index.astro # 取得の確認用ページ使ったもの
名前 | バージョン(package.json の指定) |
|---|---|
Astro |
|
microcms-js-sdk |
|
TypeScript |
|
Node.js |
|
1. Astro のプロジェクトを作る
create-astro の minimal テンプレートでプロジェクトを作ります。minimal は、ページが1枚あるだけの最小構成のテンプレートです。
npm create astro@latest -- --template minimalTypeScript の設定は、Astro が用意している一番厳しい strict をそのまま使っています。
{
"extends": "astro/tsconfigs/strict",
"include": [".astro/types.d.ts", "**/*"],
"exclude": ["dist"]
}続いて、microCMS の公式 SDK を入れます。
npm install microcms-js-sdk2. microCMS に API を作る
microCMS の管理画面でサービスを作り、記事を入れる API を作ります。どちらも「リスト形式」で作成します。
カテゴリは記事から参照するので、先に categories を作っておきます。
categories(カテゴリ)
フィールドID | 表示名 | 種類 | 必須 |
|---|---|---|---|
| カテゴリ名 | テキストフィールド | ✓ |
blogs(記事)
フィールドID | 表示名 | 種類 | 必須 |
|---|---|---|---|
| タイトル | テキストフィールド | ✓ |
| 本文 | リッチエディタ | ✓ |
| アイキャッチ | 画像 | |
| カテゴリ | コンテンツ参照( |
API を作ったら、「サービス設定 > APIキー」で APIキーを確認します。サイトのビルドでは記事を読むだけなので、GET 権限だけのキーで足ります。
3. 環境変数を astro:env で読み込む
microCMS に接続するには、サービスドメインと APIキーの2つが必要です。
.env を用意する
リポジトリには値を空にしたひな形(.env.example)だけを置き、これを .env にコピーして実際の値を入れます。
# このファイルを .env にコピーして値を入れる(.env は git 管理外)
# サービスドメイン:https://<ここ>.microcms.io の <ここ> の部分
MICROCMS_SERVICE_DOMAIN=your-service-domain
# APIキー:microCMS管理画面 > サービス設定 > APIキー(GET権限のみでOK)
MICROCMS_API_KEY=your-api-key.env は .gitignore に入っているので、Git には含まれません。APIキーを誤ってコミットしないためです。
astro.config.mjs にスキーマを書く
Astro には、環境変数の型や必須かどうかを設定ファイルで宣言できる astro:env という仕組みがあります。これを使って、2つの変数を宣言しました。
// @ts-check
import { defineConfig, envField } from 'astro/config';
// https://astro.build/config
export default defineConfig({
site: 'https://cyber-blow.com',
// canonical・サイトマップ・内部リンクのURL表記を「/」終わりに統一する
trailingSlash: 'always',
env: {
// 未設定のままビルドすると、ここで分かりやすいエラーになる
schema: {
MICROCMS_SERVICE_DOMAIN: envField.string({ context: 'server', access: 'secret' }),
MICROCMS_API_KEY: envField.string({ context: 'server', access: 'secret' }),
},
},
});envField.string() に渡している2つの設定の意味は次のとおりです。
context: 'server':サーバー側(ビルド時)のコードでだけ使える。ブラウザに送られる JavaScript からは読めないaccess: 'secret':ビルド結果のバンドルに値を埋め込まない
宣言した変数は、astro:env/server からインポートして使います。型が付くので、変数名の打ち間違いはエディタや型チェックの時点で分かります。
また、宣言した変数が設定されていないと、ビルドの途中で足りない変数の名前つきでエラーになります。空のまま microCMS にリクエストを送ってしまい、よく分からないエラーに悩まされる、ということがありません。
この仕組みは、のちに Cloudflare Pages で環境変数の名前を間違えたときに、原因を見つける手がかりになりました(Cloudflare Pages のデプロイでハマった2つのこと)。
site と trailingSlash は、URL を https://cyber-blow.com/blog/ のように「/」終わりにそろえるための設定です。canonical やサイトマップを作る回で効いてきます。
参考:Using environment variables | Astro Docs
4. microCMS のクライアントを作る
microCMS へのアクセスは、src/lib/microcms.ts にまとめます。ページからはここの関数を呼ぶだけにしておくと、取得の条件を変えたいときに1か所の修正で済みます。
import { createClient, type MicroCMSImage, type MicroCMSListContent } from 'microcms-js-sdk';
import { MICROCMS_API_KEY, MICROCMS_SERVICE_DOMAIN } from 'astro:env/server';
const client = createClient({
serviceDomain: MICROCMS_SERVICE_DOMAIN,
apiKey: MICROCMS_API_KEY,
// 429 / 5xx のときにリトライする(ビルドが一時的なエラーで落ちないように)
retry: true,
});
export type Category = MicroCMSListContent & {
name: string;
};
export type Blog = MicroCMSListContent & {
title: string;
/** リッチエディタのHTML */
content: string;
eyecatch?: MicroCMSImage;
category?: Category | null;
};
/** 全記事(本文込み) */
export function getAllBlogs(): Promise<Blog[]> {
return client.getAllContents<Blog>({
endpoint: 'blogs',
queries: { orders: '-publishedAt' },
});
}ポイントを3つ説明します。
retry: true で一時的なエラーに備える
retry: true にすると、SDK がリクエストを再試行してくれます。SDK(v3.6.0)の実装を読むと、再試行するのは 429(リクエストが多すぎる)と 5xx(サーバーエラー)のときだけで、最大2回です。404 などそれ以外の 4xx は、再試行せずにすぐエラーになります。
ビルドの途中で一時的なエラーが起きても、それだけでビルド全体が失敗しないようにするための設定です。
型は MicroCMSListContent と組み合わせる
MicroCMSListContent は、microCMS がどのコンテンツにも付ける共通の項目(id、createdAt、updatedAt、publishedAt、revisedAt)の型です。これに自分で作ったフィールドを足して、記事の型にしています。
カテゴリのような参照フィールドは、未設定のときに null が返ってくることがあるので、Category | null にしています。
getAllContents で全件を取る
microCMS の一覧取得 API は、1回のリクエストで返す件数が limit で決まります。初期値は10件、上限は100件です。
getAllContents は、この上限を気にせず全件を取ってくれる関数です。SDK の実装では、まず件数だけを問い合わせ、そのあと100件ずつ offset をずらして取得しています(リクエストの間には1秒の待ち時間が入ります)。静的サイトでは全記事のページをビルド時に作るので、記事が100件を超えても取りこぼさないこの関数が便利です。
orders: '-publishedAt' は、公開日の新しい順という意味です。フィールド名の先頭に - を付けると降順になります。
参考:一覧取得API | microCMS ドキュメント、microcms-js-sdk | GitHub
5. トップページで取得を確かめる
最後に、トップページで記事のタイトルを並べて、取得できているかを確かめます。
---
import { getAllBlogs } from '../lib/microcms';
// microCMS から記事を取得できているかの確認用
const blogs = await getAllBlogs();
---
<html lang="ja">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<title>cyber-blow</title>
</head>
<body>
<h1>cyber-blow</h1>
<ul>
{blogs.map((blog) => <li>{blog.title}</li>)}
</ul>
</body>
</html>--- で囲んだ部分(フロントマター)は、ビルド時(開発中は開発サーバー上)に実行されます。ここで await して記事を取得し、下の HTML で使います。静的サイトとして出力するので、ブラウザから microCMS にアクセスすることはなく、APIキーがブラウザに渡ることもありません。
npm run dev で開発サーバーを起動し、http://localhost:4321 を開いて、microCMS に入れた記事のタイトルが並べば接続できています。
注意点・ハマりどころ
astro.config.mjs の中では astro:env は使えない
astro:env/server からのインポートが使えるのは、ページやコンポーネント、そこから読み込むモジュールの中だけです。astro.config.mjs やビルド用のスクリプトの中では使えないので、そこで環境変数が必要になったら process.env などで読みます。
.env はデプロイ先に届かない
.env は Git に含めていないので、GitHub と連携してビルドするホスティングサービスには届きません。デプロイ先では、管理画面で同じ名前の環境変数を別に設定する必要があります。
fields や orders の綴りを間違えてもエラーにならない
microCMS は、orders や fields などに存在しないフィールド名を指定してもエラーを返しません。たとえば orders: '-publishedAt' の綴りを間違えても、並び順が期待どおりにならないだけで、ビルドは通ります。
このサイトでは、各 API にダミーのコンテンツを公開し、API が返す JSON を見てフィールド名と型がコードと合っているかを確認しました。
まとめ
npm create astro@latest -- --template minimalで最小構成のプロジェクトを作った- microCMS に
categoriesとblogsの API を作った(どちらもリスト形式) - サービスドメインと APIキーは
astro:envで宣言し、型と必須チェックを付けた microcms-js-sdkのgetAllContentsで、件数の上限を気にせず全記事を取得した
次回は、取得した記事から記事一覧・記事詳細・ページ送りを作ります。→ 第2回:記事一覧・記事詳細・ページ送り