microCMSのコンテンツをmarkdownファイルで取得する方法

microCMSのAPIでコンテンツを取得して、それぞれエンドポイントごとに個別のファイルを作成する必要ことがあった。取得したファイルを編集するため、HTMLではなく、markdownファイルで取得する必要があった。その時の記録を残しておく。
なお、npmは使わず、CDNのみを利用するため、Nodeやwebpackがわからない人もこの方法で取得できる。
## microCMS
まずは、microCMSのAPI取得である。公式ドキュメントにもあるように、`serviceDomain` と `apiKey` を利用して取得できる。このapiKeyには2種類でもある。X-API-KEYとX-GLOBAL-DRAFT-KEYである。
GETによる取得は前者のX-API-KEYを利用し、下書きコンテンツも含めて取得する場合はX-GLOBAL-DRAFT-KEYを利用する。

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

今回はX-API-KEYを利用する。
まずは、htmlのCDNでmicroCMSを読み込み、jsファイルにimportする。jsファイルではclientでドメインとAPIキーと共に初期化する。

```html:index.html
<script src="https://unpkg.com/microcms-js-sdk@latest/dist/umd/microcms-js-sdk.js"></script>
```
```js:main.js
const { createClient } = microcms;
const client = createClient({
  serviceDomain: "ドメイン",
  apiKey: "ご自身のX-API-KEY"
  });
```
https://document.microcms.io/tutorial/javascript/javascript-top

次に、`GET /api/v1/{endpoint}` の形式で取得する。`client.get`ではendpointに配列からそれぞれの値を取得する。取得したオブジェクトは定数`materialContents`に保存する。`await`で記述するのはこの関数を次に、関数で`async`を定義しているからだ。

```javascript:main.js
const endpointArray = ['category1','category2','category3'];
const category = endpointArray[1];
const data = await client.get({
  endpoint: category,
  queries: {
    offset,
    limit
  }
})

const materialContents = data.contents;
```
`materialContents` に保存するオブジェクト内に必要なデータはタイトル、記述したコンテンツブロックである。以下のようにオブジェクトは取得できる。
![object.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/926931/d29c759c-5069-ccd6-e20d-f4d41ffe1451.jpeg)


## turndownService
取得したHTMLをmarkdown化するのが **Turndown** というモジュールである。

https://github.com/mixmark-io/turndown

これもCDNで利用できる。下にあるCDNはこのTurndownのプラグインでこれがあることでテーブルタグもhtmlからmarkdowｎ表記に変更できる

```html:index.html
    <script src="https://unpkg.com/turndown/dist/turndown.js"></script>
    <script src="https://unpkg.com/turndown-plugin-gfm/dist/turndown-plugin-gfm.js"></script>
```
https://github.com/mixmark-io/turndown-plugin-gfm

このturndownを利用して、以下のようなソースコードで取得して、その内容をマークダウン化した。
取得したオブジェクトからタイトルを取得して変数に代入する。その後、contentの配列は三項演算子でrichEditorかhtmlかで取得する内容を変更している。それらをDOMでタイトルはpタグにコンテンツブロックの内容は一つの記事ごとにまとめてdivタグに代入している。そして、タイトルに合わせた記事内容が表記されるようにappendChildでそれぞれの内容の結合を行った後、それをturndownでmarkdownにしている。

```javascript
const { createClient } = microcms;
const gfm = turndownPluginGfm.gfm;
let turndownService = new TurndownService({ headingStyle: 'atx' , codeBlockStyle: 'fenced', preformattedCode: 'true'});
turndownService.use(gfm);
// いくつかのoptionがある。headingStyle: 'atx'h2が##で表示される
const client = createClient({
  serviceDomain: env.Domain,
  apiKey: env.apiKey
  });
  const endpointArray = ['category1','category2','category3','category4','category5'];

const getAllContents = async (limit=100, offset=0) => {
  const category = endpointArray[0];//好きなendpointのカテゴリを指定する
  const data = await client.get({
    endpoint: category,
    queries: {
      offset,
      limit
    }
  })
  const materialContents = data.contents;

  const mainContent = document.getElementById("mainContent");
  materialContents.forEach(element => {
    const p = document.createElement("p");
    const div = document.createElement("div");
    let title = `# ${element.title}`;
    let chapterContets = "";
    for (let i = 0; i < element.content.length ; i++) {
      if(element.content[i]) {
        let codeBlock = (element.content[i].richEditor) ? element.content[i].richEditor : element.content[i].html;
        chapterContets += codeBlock; //各コンテンツごとに変数に格納。reduceで書いたもよかった気がする。
      }
      div.innerHTML = chapterContets;
    }
    p.innerHTML = title;
    p.appendChild(div);
    mainContent.appendChild(p);
    //mainContentに取得したデータが全て格納されている。
  });

let mainMd = turndownService.turndown(mainContent);
```

## blob
最後に、blobを用いて、htmlからmarkdown化させたmicroCMSの内容をファイルとしてダウンロードする。blobはインスタンス化する際に第1引数に変換する対象、第2引数にその形式を当てはめる。
本来はmd拡張子にしたかったが、確認できなかったため、txt取得する。もちろんファイルの中身はhtmlをそのままmarkdown化させているので大きな問題はない。
また、目的としてファイルダウンロードができれば、問題ないのでブラウザでhtmlを開いたら、目的のエンドポイントごとにmarkdown化されたファイルを取得できるようにした。
それを踏まえたのが下記のようなコードである。microCMSから取得したデータが格納されたpタグを生成した `mainContent` をまず、marakdown化して、その内容をblobで変換している。

```javascript:main.js
const { createClient } = microcms;
const gfm = turndownPluginGfm.gfm;
let turndownService = new TurndownService({ headingStyle: 'atx' , codeBlockStyle: 'fenced', preformattedCode: 'true'});
turndownService.use(gfm);
// headingStyle: 'atx'h2が##で表示される
const client = createClient({
  serviceDomain: env.Domain,
  apiKey: env.apiKey
  });
const endpointArray = ['category1','category2','category3','category4','category5'];

const getAllContents = async (limit=100, offset=0) => {
  const category = endpointArray[0];
  const data = await client.get({
    endpoint: category,
    queries: {
      offset,
      limit
    }
  })
  const materialContents = data.contents;
  const mainContent = document.getElementById("mainContent");
  materialContents.forEach(element => {
    const p = document.createElement("p");
    const div = document.createElement("div");
    let title = `# ${element.title}`;
    let chapterContets = "";
    for (let i = 0; i < element.content.length ; i++) {
      if(element.content[i]) {
        let codeBlock = (element.content[i].richEditor) ? element.content[i].richEditor : element.content[i].html;
        chapterContets += codeBlock; 
      }
      div.innerHTML = chapterContets;
    }
    p.innerHTML = title;
    p.appendChild(div);
    mainContent.appendChild(p);
    //mainContentに取得したデータが全て格納されている。
  });

  let mainMd = turndownService.turndown(mainContent);
  const blob = new Blob([mainMd],{type: 'text/plain' });
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = `${category}.txt`;
  link.click();

  if (data.offset + data.limit < data.totalCount) {
    const contents = await getAllContents(data.limit, data.offset + data.limit)
    return [ ...data.contents, ...contents ]
  }
  return data.contents
}
getAllContents();

```

## まとめ
このように、microCMSのAPIを元になかなか行わないであろうHTMlからmarkdownファイルへの変換を行うことができた。また、CDNなのでnpmでNode環境を利用しないことも簡潔で良いだろう。ただ、ネストを深めれば、カテゴリ用の配列から手動で行わずにファイルを取得する方法もあったり、無駄に冗長になった処理もあるのでコードのシェイプアップする必要はある。
こちらがgithubのソースコードである。

https://github.com/Kyosuke-Kaneko/microCMS-Html2Markdown