microCMS を触る
Next、Vercel 連携ブログ
API を叩いてデータが取れる
fetch('https://example.microcms.io/api/v1/example', {
headers: {
'X-API-KEY': 'dc59f358-4622-471f-8d1e-6c7a6f969558'
},
})
.then(res => res.json())
.then(res => console.log(res));
HPにサンプルがあるので叩いてみた
料金
無料でいろいろできそう
新規登録
メアドとパスワードを入れると、メールで確認コードが飛んでくる
入力したら完了
まずはコンテンツ作成
サービス名とサービスIDを入力
画像は良い感じのがなかったのでスキップ
料金選択は Hobby を選択
API の作成
適当に API 名とエンドポイントを設定
API の型はブログの一覧を取るAPIなので、リスト形式を指定
API スキーマを設定
ブログのタイトルや画像、カテゴリを配列で指定してみた
コンテンツを追加する
最初は空なので追加する
適当に値を埋めて公開
プレビューで動作確認
一覧用のAPIだが、blog/${id}
で叩くと単体でデータが取れる
これは便利(使い手がやりたいことをわかっている)
コンテンツの参照
返却する API を作っていると思い、カテゴリを直接配列で指定していたが、コンテンツの参照をすることができる
カテゴリ API を作って
ブログのカテゴリはカテゴリAPIを参照する
RDB 的な考えというか、API というよりテーブルを作っている感覚になる
API 数は Hobby, Standard では 10 個まで作れる(11個から課金)なので、無闇に増やせないが良い機能
Next.js と連携
トップ
3件だけ表示し、詳細とブログ一覧へのリンクを設置
型定義とか消しているがコード
limit
で3件に絞っている
export default function Index(props: Props) {
const { blogList } = props;
return (
<div className={styles.container}>
<h1>microCMS Next.js Sample</h1>
<ul className={styles.list}>
{blogList.map(blog => (
<li key={blog.id} className={styles.item}>
<Link href={`/blogs/${blog.id}`}>
<a className={styles.link}>
<div className={styles.imgWrap}>
<Image
src={blog.img.url}
layout="fill"
objectFit="contain"
/>
</div>
<p>{blog.title}</p>
{blog.categoryList.map(category => (
<span key={category.id}>{category.name}</span>
))}
</a>
</Link>
</li>
))}
</ul>
<Link href="/blogs">more</Link>
</div>
)
}
export const getStaticProps = async () => {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}blog?limit=3`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
return {
props: {
blogList: data.contents,
},
};
};
ブログ一覧
limit
を指定していないので 10 件表示される
ほぼトップと同じ
export default function Blogs(props: Props): JSX.Element {
const { blogList } = props;
return (
<div className={styles.container}>
<h1>Blogs</h1>
<ul className={styles.list}>
{blogList.map(blog => (
<li key={blog.id} className={styles.item}>
<Link href={`/blogs/${blog.id}`}>
<a className={styles.link}>
<div className={styles.imgWrap}>
<Image
src={blog.img.url}
layout="fill"
objectFit="contain"
/>
</div>
<p>{blog.title}</p>
{blog.categoryList.map(category => (
<span key={category.id}>{category.name}</span>
))}
</a>
</Link>
</li>
))}
</ul>
</div>
)
}
export const getStaticProps = async (): Promise<{
props: Props
}> => {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}blog`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
return {
props: {
blogList: data.contents,
},
};
};
ブログ詳細
詳細を表示
ブログの本文を microCMS 上でエディター使って書けるので dangerouslySetInnerHTML
を利用して表示している
export default function Blog(props: Props): JSX.Element {
const { blog } = props;
return (
<div className={styles.container}>
<h1>{blog.title}</h1>
<Image
src={blog.img.url}
width={blog.img.width}
height={blog.img.height}
/>
<div>
{blog.categoryList.map(category => (
<span key={category.id}>{category.name}</span>
))}
</div>
<div
dangerouslySetInnerHTML={{
__html: `${blog.body}`,
}}
/>
</div>
)
}
export async function getStaticPaths() {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}blog`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
const paths = data.contents.map(blog => `/blogs/${blog.id}`);
return {
paths,
fallback: false,
};
}
export const getStaticProps = async ({ params }): Promise<{
props: Props
}> => {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}blog/${params.id}`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
return {
props: {
blog: data,
},
};
};
カテゴリー一覧
ブログの一覧と同様カテゴリを取得して表示
export default function Categories(props: Props): JSX.Element {
const { categoryList } = props;
return (
<div className={styles.container}>
<h1>Categories</h1>
<ul className={styles.list}>
{categoryList.map(category => (
<li key={category.id} className={styles.item}>
<Link href={`/categories/${category.id}`}>
<a className={styles.link}>
<p>{category.name}</p>
</a>
</Link>
</li>
))}
</ul>
</div>
)
}
export const getStaticProps = async (): Promise<{
props: Props
}> => {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}category`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
return {
props: {
categoryList: data.contents,
},
};
};
カテゴリ詳細
カテゴリに紐づくブログのみを表示する
filters
とうクエリがあり、これを利用するとフィールドの値で検索して取得ができる
なおコンテンツ参照については単数の場合は[equals](例:category[equals]uN28Folyn)、複数の場合は[contains]のみが利用可能です。(例:tags[contains]oJIZmiban)
とのことだったので、今回のカテゴリはコンテンツ参照の複数なので下記のクエリでブログを取得している
blog?filters=categoryList[contains]9s79kn-7kx
export default function Category(props: Props): JSX.Element {
const { blogList, category } = props;
return (
<div className={styles.container}>
<h1>{category.name}</h1>
<ul className={styles.list}>
{blogList.map(blog => (
<li key={blog.id} className={styles.item}>
<Link href={`/blogs/${blog.id}`}>
<a className={styles.link}>
<div className={styles.imgWrap}>
<Image
src={blog.img.url}
layout="fill"
objectFit="contain"
/>
</div>
<p>{blog.title}</p>
{blog.categoryList.map(category => (
<span key={category.id}>{category.name}</span>
))}
</a>
</Link>
</li>
))}
</ul>
</div>
)
}
export async function getStaticPaths() {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}category`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
const paths = data.contents.map(category => `/categories/${category.id}`);
return {
paths,
fallback: false,
};
}
export const getStaticProps = async ({ params }): Promise<{
props: Props
}> => {
const res = await fetch(`${process.env.MICROCMS_ENDPOINT}blog?filters=categoryList[contains]${params.id}`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const data = await res.json();
const resCategory = await fetch(`${process.env.MICROCMS_ENDPOINT}category/${params.id}`, {
headers: {
'X-API-KEY': process.env.MICROCMS_API_KEY
},
});
const dataCategory = await resCategory.json();
return {
props: {
blogList: data.contents,
category: dataCategory
},
};
};
Vercel でリリース
一瞬で完了
全てSSGで作っているので、ブログ情報の追加・更新・削除でビルドを走らせる必要がある
vercel の Git -> Deploy Hooks で Webhook を作る
Webhook の URL が発行されるので、microCMS 側の Webhook の設定を行う
カスタム通知を選択
コンテンツの公開時・更新時、コンテンツの削除時を選択(適当)
データのインポート
WRITEリクエスト数は無料だと月100回しか叩け無い
APIが空の時はCSVでインポートできる
参照系は参照先のIDを渡せば参照してくれるので便利
画像だけインポートができない
SDK がでていた
import { createClient } from 'microcms-js-sdk';
const client = createClient({
serviceDomain: process.env.MICROCMS_ENDPOINT,
apiKey: process.env.MICROCMS_API_KEY,
});
// 全取得
export const getAllWorkList = async (): Promise<Work[]> => {
const response = await client.get({
endpoint: 'works',
}) as {
contents: Work[]
};
return response.contents;
};
// 5件だけ取得
export const getWorks = async (): Promise<Work[]> => {
return await client.get({
endpoint: 'works',
queries: { limit: 5 },
});
};
// 1件だけ取得
export const getWork = async (id: Work['id']): Promise<Work> => {
return await client.get({
endpoint: 'works',
contentId: id,
});
};
画像を複数持たせたい時は、画像のカスタムフィールドを作り、カスタムフィールドの繰り返しを指定すればできる