React.jsからAsync, Awaitを使ってNode.jsのExpressで立てたAPIサーバーにアクセスしてMongoDBのデータをFetchする話

ちょっとしたツールを作っていて、普段使っているRDBではなく、MongoDBを使うべきだなぁってシーンが有ったのでNode.jsとMongoDBにReact.jsからアクセスした流れとかを書いていきます。
といっても、今回書こうと思っているのはReact.jsでAPIにアクセスするあたりの処理がメインなので、Node.js Express MongoDBあたりはサクッと紹介していこうかなぁと。

環境はDockerで構築したので、それっぽいものをGithubにPushしておきました。 github.com こんな感じの構成です

  • Nginx
  • MongoDB
  • MongoExpress
  • React.js
  • Material-ui
  • Webpack

Node.jsとExpressとMongoDBを使ったAPIサーバーの設定

APIの数が少なかったので、横着して簡単に書いてますが、以下の項に /expressDir/route/index.html にべた書きしちゃってます。

const Mongo = require('mongodb');
const MongoClient = Mongo.MongoClient;
// docker-composeを利用しているため、以下のようなURLを指定している
// 同一のサーバーに立てるのであれば、localhostで良いはず
const _url = 'mongodb://tm_mongodb:27017/feed';

router.get('/', (req, res, next) => {
  MongoClient.connect(_url, (err, client) => {
    const db = client.db('feed');
  
    db.collection('feed', (err, collection) => {
      collection.find().sort({ 'feed.id_str': -1 }).toArray((err, docs) => {
        res.send(docs);
      });
    });
  });
});

こんな感じにすると、JavaScript側からGETで http://localhost:3000/ にアクセスすると、feedの一覧が取得できます。

なお、Node.jsはプロセスを立ち上げているとファイルの更新をしても処理が変更されないので、大抵は更新検知するプロセスからNode.jsを実行します。 今回利用したのはnodemonというものでしたが、これが自分のDocker環境でうまくファイル更新を検知してくれなかったのですが、以下のような設定を追加すると動いたので備忘録的に残しておきます。

package.json のscripts部分にnodemonを絡めた実行コードを記述すると思うのですが、そこで --legacy-watch パラメーターを追加してやるといい感じにやってくれます。

React.jsでAPIにアクセスする

React.jsでAjaxを使う場合、ちょっと前までは「ここだけjQuery使うのかよ、FetchAPIもまだ怪しいし」みたい話を聞いたことがあったのですが、現在は使いやすい物があるみたいです。 github.com 今回はこのsuperagentを利用しました。

非同期処理なのでasync awaitを使って書いてあります。
API関係のコードはすべて api.js というファイルに纏めて記述します。

import request from 'superagent';
const url = 'http://localhost';
export const getAllFeed = async () => {
  const endPoint = url;
  try {
    const res = await request.get(endPoint);
    return res.body;
  } catch (error) {
    console.log(error);
    return {};
  }
};

呼び出す側はComponentが読み込まれた際に実行してもらいたいので、 componentDidMount() 内に記載します。

componentDidMount() {
    // すべてのFeedを取得
    getAllFeed()
      .then((feed) => {
        this.setState({ feed });
      });
}

以上がComponentが読み込まれた際、MongoDB側からFeedを取得して、React.jsでsetStateする部分の処理になります。

React.jsは勉強中で、それまではFirebaseを使ってデータを格納していたこともあり、Async, Await系の処理を書いたことがありませんでしたが、思ったよりも簡単にかけてスッキリするので良いです。
Firebaseはそれはそれですごく使いやすいのですが、Realtime Databaseが必要ではないときと、まぁ費用がかかりそうなときは今回作ったDockerファイルあたりを駆使して、MongoDBとExpressを使ってサクッとAPIサーバーを立ててもいいかもしれませんね。