連載「Astro × microCMS でブログを作る」第1回

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

^7.4.2

microcms-js-sdk

^3.6.0

TypeScript

^6.0.3

Node.js

>=22.23.4(engines で指定)

1. Astro のプロジェクトを作る

create-astro の minimal テンプレートでプロジェクトを作ります。minimal は、ページが1枚あるだけの最小構成のテンプレートです。

npm create astro@latest -- --template minimal

TypeScript の設定は、Astro が用意している一番厳しい strict をそのまま使っています。

tsconfig.json
{
  "extends": "astro/tsconfigs/strict",
  "include": [".astro/types.d.ts", "**/*"],
  "exclude": ["dist"]
}

続いて、microCMS の公式 SDK を入れます。

npm install microcms-js-sdk

参考:Install Astro | Astro Docs

2. microCMS に API を作る

microCMS の管理画面でサービスを作り、記事を入れる API を作ります。どちらも「リスト形式」で作成します。

カテゴリは記事から参照するので、先に categories を作っておきます。

categories(カテゴリ)

フィールドID

表示名

種類

必須

name

カテゴリ名

テキストフィールド

✓

blogs(記事)

フィールドID

表示名

種類

必須

title

タイトル

テキストフィールド

✓

content

本文

リッチエディタ

✓

eyecatch

アイキャッチ

画像

category

カテゴリ

コンテンツ参照(categories)

API を作ったら、「サービス設定 > APIキー」で APIキーを確認します。サイトのビルドでは記事を読むだけなので、GET 権限だけのキーで足ります。

3. 環境変数を astro:env で読み込む

microCMS に接続するには、サービスドメインと APIキーの2つが必要です。

.env を用意する

リポジトリには値を空にしたひな形(.env.example)だけを置き、これを .env にコピーして実際の値を入れます。

.env.example
# このファイルを .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つの変数を宣言しました。

astro.config.mjs
// @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か所の修正で済みます。

src/lib/microcms.ts
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. トップページで取得を確かめる

最後に、トップページで記事のタイトルを並べて、取得できているかを確かめます。

src/pages/index.astro
---
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回:記事一覧・記事詳細・ページ送り