841-biborokuWebフロントエンドの備忘録

ブログをAstro v5 Content Loader API・microCMSにリニューアル - Zodの型定義編 -

この備忘録ブログを最初に作ったときはNext.js(Pages Router)を採用していましたが、このたび心機一転、Astro v5 へリニューアル中です🎈

今回は、microCMS公式ブログの「AstroとmicroCMSでブログサイトを作ってみよう(Astro 5以降のコンテンツローダー対応版)」を参考に進めています。

基本的には公式記事に沿って進めればOKですが、自身のmicroCMSのAPI設定に合わせてカスタマイズした部分(特にZodでの型定義)を中心に、備忘録としてまとめておきます。

今回は「型定義」と「Content Layerでの取得設定」までを進めました。

共通フィールドの型定義

microCMSの全コンテンツに共通する日付フィールドやコンテンツIDなどの型を定義します。


// microCMSIDフィールドのスキーマ
export const microCMSContentIdScheme = z.object({
  id: z.string(),
}) satisfies z.ZodType<MicroCMSContentId>;

// microCMS日付フィールドのスキーマ
const microCMSDateScheme = z.object({
  createdAt: z.string().datetime(),
  updatedAt: z.string().datetime(),
  publishedAt: z.string().datetime().optional(),
  revisedAt: z.string().datetime().optional(),
}) satisfies z.ZodType<MicroCMSDate>;

画像データの型定義

// microCMS画像フィールドのスキーマ
const MicroCMSImageSchema = z.object({
  url: z.string().url(),
  width: z.number(),
  height: z.number(),
  alt: z.string().optional().default(""),
}) satisfies z.ZodType<Partial<MicroCMSImage> & { alt?: string }>;

【おさらい】よく使うZodの型指定

設定中に「これなんだっけ🤔?」となりがちな、Zodの書き方とTypeScript型の対応表です。

データの内容

Zodの書き方(z.)

TypeScriptでの型

数値

number()

number

整数(小数不可)

number().int()

number

文字列

string()

string

真偽値

boolean()

boolean

日付

date()

Date

配列

array(z.string())

string[]

列挙型

enum(["a", "b"])

"a" | "b"

未定義を許容

.optional()

? (optional)

nullを許容

.nullable()

| null

カスタムフィールドの型を定義する

microCMSで作成したカスタムフィールドに合わせて、個別にスキーマを作成します。

1. カスタムフィールドID(fieldId)

string() でも動作しますが、より厳密にするために.literalでフィールドIDを指定しています。

const MetadataSchema = z.object({
  fieldId: z.literal("metadata"),
  title: z.string().optional(),
  description: z.string().optional(),
});

2. セレクトフィールド(複数選択)

複数選択がONでもOFFでも、APIからの戻り値は配列(array)になります。

const HighlightSchema = z.object({
  // 略
  lang: z.array(
    z.enum(["javascript", "tsx", "typescript", "jsx"])
  ).optional(),
});

3. 繰り返しフィールド

「繰り返し」は、定義したカスタムフィールドのいずれかに当てはまれば良いため、z.unionを使って定義し、全体をz.arrayで囲みます。

const sectionSchema = z.array(
  z.union([
    HighlightSchema,
    GallerySchema,
    // 他のカスタムフィールドもここに追加
  ])
).nonempty(); // 必須項目の場合はnonempty()

コンテンツAPIのスキーマを定義

これまでに作った部品を組み合わせて、最終的なコレクションのスキーマを完成させます。

カテゴリー用

作成したフィールドにmicroCMSの日付・コンテンツIDの型をマージします。

const CategorySchema = z.object({
  title: z.string(),
  slug: z.string(),
})
.merge(microCMSContentIdScheme)
.merge(microCMSDateScheme);

記事(Articles)用

「複数コンテンツ参照」のカテゴリーや、先ほどの「繰り返しフィールド」を組み込みます。

const ArticlesSchema = z.object({
  // 略
  title: z.string(),
  category: z.array(CategorySchema), // 複数参照なのでarray
  section: sectionSchema,
  metadata: MetadataSchema, // 未入力でもfieldIdは返るのでoptionalなし(※1)
})
.merge(microCMSContentIdScheme)
.merge(microCMSDateScheme);

※1…エラーが出る場合は.optional().nullable()を追加
一部記事で戻り値がnullになっているデータがありました。途中でカスタムフィールドを追加したからなのか、戻り値の仕様が途中で変わったのか定かではありません。
一度該当フィールドにデータを入れて公開⇒削除して公開するとnullからオブジェクトに変わりました。

AstroのContent Collectionを設定する

最後にsrc/content/config.tsで、Astro v5のloaderを使って定義します。

export const collections = {
  articles: defineCollection({
    loader: microCMSLoader({
      endpoint: "articles", // 記事用のエンドポイント
    }),
    schema: ArticlesSchema,
  }),
  categories: defineCollection({
    loader: microCMSLoader({
      endpoint: "categories", // カテゴリ用のエンドポイント
    }),
    schema: CategorySchema,
  }),
};

このローダー関数の中で getAllContents() を使って全件取得してくれているので、個別に取得ロジックを書く必要がなく、とても簡単です🎉

※この関数は、冒頭でも紹介した microCMSの参考ブログ記事 から引用させていただきました。

まとめ

今回は型定義を中心にまとめました。

Zodでしっかり型を固めておくと、コンポーネント側でデータを使う時に補完が効いて開発がとても楽になりそうです😇

次回は、これらのデータを使って実際に記事画面を出力する部分について書きたいと思います。

📝参考サイト

シェア