Closed14

microCMS を触る

Wataru TaguchiWataru Taguchi

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にサンプルがあるので叩いてみた

Wataru TaguchiWataru Taguchi

まずはコンテンツ作成

サービス名とサービスIDを入力

画像は良い感じのがなかったのでスキップ

料金選択は Hobby を選択


Wataru TaguchiWataru Taguchi

API の作成

適当に API 名とエンドポイントを設定

API の型はブログの一覧を取るAPIなので、リスト形式を指定

API スキーマを設定

ブログのタイトルや画像、カテゴリを配列で指定してみた

Wataru TaguchiWataru Taguchi

コンテンツを追加する

最初は空なので追加する

適当に値を埋めて公開

プレビューで動作確認

一覧用のAPIだが、blog/${id} で叩くと単体でデータが取れる

これは便利(使い手がやりたいことをわかっている)

Wataru TaguchiWataru Taguchi

コンテンツの参照

返却する API を作っていると思い、カテゴリを直接配列で指定していたが、コンテンツの参照をすることができる

カテゴリ API を作って

ブログのカテゴリはカテゴリAPIを参照する

RDB 的な考えというか、API というよりテーブルを作っている感覚になる

API 数は Hobby, Standard では 10 個まで作れる(11個から課金)なので、無闇に増やせないが良い機能

Wataru TaguchiWataru Taguchi

Next.js と連携

https://github.com/tiwuofficial/microcms-next

トップ

3件だけ表示し、詳細とブログ一覧へのリンクを設置

型定義とか消しているがコード

limit で3件に絞っている

https://document.microcms.io/content-api/get-list-contents#h4cd61f9fa1

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,
    },
  };
};

カテゴリ詳細

カテゴリに紐づくブログのみを表示する

https://document.microcms.io/content-api/get-list-contents#hdebbdc8e86

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
    },
  };
};
Wataru TaguchiWataru Taguchi

Vercel でリリース

一瞬で完了

https://microcms-next-red.vercel.app/

全てSSGで作っているので、ブログ情報の追加・更新・削除でビルドを走らせる必要がある

vercel の Git -> Deploy Hooks で Webhook を作る

Webhook の URL が発行されるので、microCMS 側の Webhook の設定を行う

カスタム通知を選択

コンテンツの公開時・更新時、コンテンツの削除時を選択(適当)

Wataru TaguchiWataru Taguchi

データのインポート

WRITEリクエスト数は無料だと月100回しか叩け無い

APIが空の時はCSVでインポートできる

参照系は参照先のIDを渡せば参照してくれるので便利

画像だけインポートができない

Wataru TaguchiWataru Taguchi
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,
  });
};

Wataru TaguchiWataru Taguchi

画像を複数持たせたい時は、画像のカスタムフィールドを作り、カスタムフィールドの繰り返しを指定すればできる

このスクラップは2021/06/06にクローズされました