Next.jsのサイトにmicroCMSをAPI接続する

今回はこのようなサイト内のニュース欄をmicroCMSを用いて作ります。
デプロイはAWS amplifyでする前提です。![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/544f86a4-f023-2be0-f58f-30dd26881813.png)

# microCMSの設定
### (1)プロジェクトを作る
![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/64b5ad1c-e34a-1256-4f74-bd19e9c0be34.png)
![image (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/198e16e1-373c-0292-dc6a-63e73cfe4d57.png)
個人開発レベルではHobbyで事足りるかと（検証中）。

### (2)APIを作成
![image (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/d01f5f75-6416-cf6a-0c45-e34664b452e5.png)

リスト形式を選択
![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/3cd38d8e-0d1c-429f-207c-89d9ff3391d0.png)

### (3)投稿したい項目を定義
![image (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/52067d96-0e88-ef85-8ef1-ede2d6da3b27.png)

# APIで取得したデータをmapで出す
### (1)API keyを.envに書き込む

```env:.env.production
NEXT_PUBLIC_API_KEY=your key
```

keyはこちら
![2021_06_30_16_38_33_管理画面_microCMS (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/6f4a10dc-622e-83a1-3271-7dfed4fc39e0.png)
![2021_06_30_16_40_27_.env.production_it_feels_it_Visual_Studio_Code (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/b40f8a62-1b91-edfc-2903-6f1b9e6bd605.png)

### (2)nextがexport出来るようにする

```js:next.config.js
module.exports = {
  env: {
    MICROCMS_API_KEY: process.env.X_API_KEY,
  },
}
```

### (3)pages/index
componentに書き込んでも、なぜかうまく動作しないので、直接pagesに書き込むことをお勧めします。

```tsx:pages/index.tsx
import styles from '../styles/Home.module.scss'
import Link from 'next/link'
import React from 'react'
import Moment from 'react-moment'
import Icon from '../components/bases/IconCompo'
​
export const getStaticProps = async () => {
  const key = {
    headers: { 'MICROCMS-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  try {
    const news = await (await fetch('https://it-feels-it.microcms.io/api/v1/news', key)).json()
    return {
      props: {
        news: news.contents,
      },
    }
  } catch (error) {
    console.error(error)
  }
}
const Home = ({ menu, news, staff }) => {
  return (
      <div className={styles.news}>
        <p className={styles.title}>ニュース</p>
        <div className={styles.newsContainer}>
          {news.slice(0, 4).map((news) => (
            <Link href={`news/${news.id}`} key={news.id}>
              <div className={styles.item}>
                <tr>
                  <td className={styles.date}>
                    <Moment format="YYYY/MM/DD" style={{ marginRight: 30, color: '#a1a1a1;' }}>
                      {news.date}
                    </Moment>
                  </td>
                  <td className={styles.body}>{news.title}</td>
                </tr>
              </div>
            </Link>
          ))}
        </div>
        <button className={styles.moreContainer}>
          <span>
            もっと見る
            <Icon type="arrowRight" />
          </span>
        </button>
    </div>
  )
}
​
export default Home
```
・apiURLはこのページから取得します
![2021_06_30_16_40_27_.env.production_it_feels_it_Visual_Studio_Code (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369162/97deffbc-81d1-a5c5-cf5a-4e20bed994b8.png)

・Momentは、別記事で紹介してます。
・.slice(0,4)は、直近の1番目から4番目までだけを表示します。


### (4)CSS

```scss
.news {
    text-align: center;
    padding-top: 2%;
    .title {
      font-size: 30px;
      font-weight: bold;
    }
    .newsContainer {
      width: 50%;
      margin: 0 auto;
      border-top: solid 1px #e8e8e8;
      .item {
        width: 100%;
        border-bottom: solid 1px #e8e8e8;
        tr {
          td {
            cursor: pointer;
            padding: 23px;
            font-weight: bold;
            text-align: left;
          }
        }
      }
    }
    .moreContainer {
      margin: 0 auto;
      padding: 20px 0;
      span {
        display: flex;
        justify-content: center;
        align-items: center;
        font-family: 'ten mincho text';
        font-size: 15px;
        font-weight: bold;
        color: #606060;
      }
    }
 ```
これで外観は完成したかと思います。

### (4)詳細を表示するページを作る
ニュースのタイトルをクリックしたときに、その詳細を表示させるページを作ります。
pages/newsを作成

```tsx:pages/news/[id].tsx
import styles from './id.module.scss'
import Moment from 'react-moment'

type Props = InferGetStaticPropsType<typeof getStaticProps>

export interface News {
  id: string
  createdAt: string
  updatedAt: string
  publishedAt: any
  revisedAt: string
  title: string
  date: string
  thumbnail?: thumbnailTag
  body: string
}

export interface thumbnailTag {
  url: string
  width: number
  height: number
}
export const getStaticPaths = async () => {
  const key = {
    headers: { 'MICROCMS-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  const data = await fetch('https://examplerenren.microcms.io/api/v1/news', key)
    .then((res) => res.json())
    .catch((err) => console.warn(err))
  const paths = data.contents.map((content) => `/news/${content.id}`)
  return { paths, fallback: false }
}

export const getStaticProps = async (context) => {
  const id = context.params.id
  const key = {
    headers: { 'MICROCMS-API-KEY': process.env.NEXT_PUBLIC_API_KEY },
  }
  const data: News = await fetch('https://examplerenren.microcms.io/api/v1/news/' + id, key)
    .then((res) => res.json())
    .catch((err) => console.warn(err))
  return {
    props: {
      news: data,
    },
  }
}

const NewsId: NextPage<Props> = ({ news }) => {
  return (
    <div>
          <div className={styles.contents}>
            <h1 className={styles.title}>{news.title}</h1>
            <Moment format="YYYY/MM/DD" className={styles.date}>
              {news.publishedAt}
            </Moment>
            <div className={styles.imgContainer}>
              <img src={news.thumbnail.url} className={styles.thumbnail}></img>
            </div>
            <div
              className={styles.body}
              dangerouslySetInnerHTML={{
                __html: `${news.body}`,
              }}
            />
          </div>
    </div>
  )
}
export default NewsId
```

これで表示できると思います。
getStaticPropsのところのapiのURLの最後に/を追加するのを忘れないでください。
1日ハマりました。