PleasanterをヘッドレスCMSとして活用する

# 前置き
タイトルの通り、PleasanterをヘッドレスCMSとして活用する方法を紹介します。

いわゆる「ヘッドレスCMS」と検索すると、以下のような図がいっぱい出てきます。（下の図は自作）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/f2f469bf-8625-4940-5563-c70a11cb7614.png)
これの、バックエンドをPleasnaterでやってみようというのが今回の話です。つまり↓のようなイメージ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/63a59e14-733d-8825-b8f3-6a5b4727905f.png)
[PleasanterのAPI](https://pleasanter.org/manual/api)を使って接続します。

# フロントエンドの開発
ということで、まずはフロント側の開発。今回は、Reactで作ってみます。（初学者）

[[こちら]](https://www.udemy.com/share/106JSA3@A-C0DTl79YaNzU2G3lNgghHB9D8LT_kEq6a74dFeZ29D7OT-1y_b-Us9R-AGMq4X/)のUdemy講座を参考に作ってみました。講座では3つのアプリを作っていますが、そのうちブログアプリを流用します。

講座ではバックエンドにはGoogleのFirebaseのStorageを使用していますが、これをPleasanterに置き換えてみます。なお、ブログアプリの認証にはFirebase Authenticationを使います。（講座のまま）

# 開発したもの

ホーム画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/d46916fa-0042-9cc1-f362-46d4815d2c25.png)
投稿内容をPleasanterから取得しています。レイアウトは自分なりにアレンジしてみました。

”それとなく”レスポンシブ対応
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/e18c1d62-8336-16fa-02a3-209cbbc31fe1.png)

投稿画面。Pleasanterに登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/709cd30d-7c5c-20d1-e387-512c9e48eee1.png)

# バックエンドのPleasanter
こんな感じで投稿内容を保存しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/084e9e39-d250-4532-03e4-a89ad5a9fed8.png)

Firebase AuthenticationによるGoogleアカウントの認証情報をuidに保存しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/922382/954b07ee-cee9-7600-a6eb-151fe31c316a.png)

# 実装内容
全部だとかなり多いので、Home画面のjsxのみ抜粋して記載します。
```jsx
import React, { useContext, useEffect, useState } from 'react'
import "./Home.css";
import CommonContext from './Context';

const Home = ({ authUid }) => {

    const commonContext = useContext(CommonContext);
    const [postList, setPostLists] = useState([]);

    //useEffectで画面読込時に投稿情報を取得します。
    useEffect(()=>{
        const getPosts = async ()=>{
            let resJson = await getPostList();
            setPostLists(resJson.Response.Data);
        };
        getPosts();
    },[])

    //APIでPleasanterに登録されている投稿情報を取得します。
    const getPostList = async() =>{
        console.log("apiKey=" + commonContext.ApiKey);
        let data = {
            "ApiVersion": 1.1,
            "ApiKey": commonContext.ApiKey,
            "view" : {
                "ApiDataType": "KeyValues",
                "ApiColumnKeyDisplayType": "ColumnName",
                "GridColumns": ["ResultId","Title","Body","ClassA","ClassB"]
            }
        }        

        let url = `${commonContext.PleasanterUrl}api/items/${commonContext.SiteId}/get`;
        let response = await fetch(url, {        
            method: 'POST',
            body: JSON.stringify(data),
            headers: {
                'Content-Type': 'application/json'
            },
        });
        return response.json();
    };

    const handleDelete = async (id) => {
        await deletePost(id);
        window.location.href = "/";
    }

    //APIでPleasanterに登録されている投稿情報を削除します。
    const deletePost = async(id) =>{
        let data = {
            "ApiVersion": 1.1,
            "ApiKey": commonContext.ApiKey
        }        

        let url = `${commonContext.PleasanterUrl}api/items/${id}/delete`;
        let response = await fetch(url, {
            mode: 'cors',
            method: 'POST',
            body: JSON.stringify(data),
            headers: {
                'Content-Type': 'application/json'
            },
        });
        return response.json();
    };

    return (
        <div className='homePage grid-container'>
            {/* APIで取得した投稿情報を展開する */}
            {postList.map((post)=> {
            return (
                <div className='postContents' id={post.ResultId} key={post.ResultId}>
                        <div className='postHeader'>
                            <h1>{post.Title}</h1>
                        </div>
                        <div className='postTextContainer line_wrap'>
                            {post.Body}
                        </div>
                        <div className='nameAndDeleteButton'>
                            <h3>@{post.ClassA}</h3>
                            {authUid === post.ClassB &&
                                <button onClick={()=> handleDelete(post.ResultId)}>削除</button>
                            }
                        </div>
                </div>
                )
            })}
        </div>
    )
};

export default Home;
```
getPostListでPleasanterに接続し投稿内容を取得、useStateのpostListに設定しHTMLに書き込んでいます。

# まとめ
もともとPleasanterにはAPIが豊富に存在していることから、できるだろうなー、となんとなく思っていましたが、実際作ってみたら割と簡単にできました。

# おまけ
今回、Reactを初めて触ってみましたが、結構簡単に作れるもんですね。もっといろいろ試してみたいと感じました。