StackBlitzでReactとJSON Serverを動かしてフロントエンドでAPIからデータを取得するサンプルをブラウザで全部動かす

StackBlitzを使って、ブラウザ上でReactとJSON Serverを動かして、フロントエンドからバックエンドAPIのデータを取得するサンプルを作りました。フロントエンドもバックエンドもあなたのブラウザ上で動きます。
2024.05.21

フロントエンド(React)のブログを書くのに、動かせるサンプルとして StackBlitz を使っています。

StackBlitzって何?と、思った方はこちらのブログを御覧ください。 簡単に言うと、ブラウザ上でプレビューできるオンラインのコードエディタです。

フロントエンドは、基本的にデータをバックエンドAPIから取得して表示することが多いです。 そういった機能を盛り込んだブログを書くとき、StackBlitzのサンプルのデータ取得先としてバックエンドAPIをどう準備すればいいのか?というのが、悩みでした。

解決方法の一例を上げると…

  • 適当なサンプルデータファイル作ってWeb APIから読み込んだ体にする?
    • → TypeScriptを使いたい関係上、データ取得ライブラリによってデータ取得時の型が変わるので、それに対応するのがダルい。データ取得ライブラリ(Zodiosとか)のブログ書くのには使えない。
  • Sample API的な公開サービスを利用する?
    • → CORS対応ができないことが多くて利用できない。そのサービスがいつまで使えるかわからないリスクがある。
  • 自前でAPIサーバを作る?
    • → ブログのサンプルとしてずっとWeb APIを動かし続けるのはコストがかかるので避けたい。

といろいろ考えた結果、StackBlitz上でexpressサーバーも動くわけだし、 StackBlitz上でバックエンドAPIも動かせばいいじゃない。 という結論にいたりました。

というわけで、バックエンドサーバーとして一番簡単そうな JSON Server をStackBlitzで動かしつつ、フロントエンド(React)からAPIを叩いてデータを取得するサンプルを作ったので紹介します。

最終的には、こんなものができます。 これは画面表示用のデータをStackBlitz上で動くバックエンドから取得して、フロントエンドで表示しているサンプルです。 どちらもブラウザ上で動いています。

バックエンド(JSON Server)を作る

JSON Server は、JSONファイルを置くだけで簡単にREST APIを構築できるツールです。

本番APIで利用するというよりは、モックサーバーやテスト用のAPIサーバーとしてローカルで動かして使うことが多いです。

StackBlitz上でJSON Serverを動かすのは、超簡単です。 なぜなら、初期テンプレートとしてJSON Serverのテンプレートが用意されているからです。 画面から、ぽちぽちぽち、でJSON Serverが動きます。

New projectBackend タブを選択して、 JSON Server をぽちっとするだけで、JSON Serverの環境が構築できます。

JSON Server単独で動いているStackBlitzはこちらです。 初期テンプレートからは、ちょっとデータを変えています。

(↓ RUN PROJECT をクリックすると埋め込んだStackBlitzでコードとプレビューページが表示されます)

ブラウザ上でターミナルが動かせるので、ターミナル上で npm run backend のコマンドを打てば、JSON Serverが起動します。

別ターミナルを開いて、 次のコマンドを叩くと、StackBlitz環境上でJSON Serverがレスポンスしていることがわかります。

$ curl http://localhost:3000/posts

フロントエンド(Vite + React + TypeScript)を作る

StackBlitz上でReactを動かすのも、超簡単です。 Reactの初期テンプレートも用意されています。

New projectFrontend タブを選択して、 React(TypeScript) をぽちっとするだけで、Reactの環境が構築できます。

このテンプレートでは、ビルドツールとして Vite が使われています。

特に変える理由もないので、そのままViteを使います。

フロントエンド(React)が単独で動いているStackBlitzはこちらです。 初期テンプレートからはちょっと表示を変えています。まだ、バックエンドからデータは取得していませんが、asyncな fetchApi 関数を定義して、取得している体でテーブル表示をしています。

npm workspace でモノレポ構成にする

ここまででバックエンドとフロントエンド、それぞれStackBlitz上で動かすことができました。

次はこの2つを、1つのStackBlitz環境で動かします。

2つのアプリケーションを1つのプロジェクトとして動かすので、 npm workspace を使ってモノレポ構成にします。

こういうフォルダ構成です。

.
├── package.json
├── backend ... バックエンド(JSON Server)
│   └── package.json
└── frontend ... フロントエンド(Vite + React)
    └── package.json

トップフォルダの package.json はこんな感じにして、workspaceに backendfrontend の2つのディレクトリを指定します。

package.json

{
  "name": "react-backend-sample",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "npm run frontend",
    "frontend": "npm run -w frontend dev",
    "backend": "npm run -w backend backend"
  },
  "workspaces": ["backend", "frontend"]
}

backendfrontend のディレクトリには先程作った環境をそれぞれ入れて、とりあえず1つのプロジェクトにできました。

StackBlitzを開いたときは npm run dev が実行されるので、とりあえずフロントエンドを起動するようにnpmコマンドを設定しておきます。

データ取得は、フロントエンド(React)のコードを変更して、バックエンドの db.json からインポートするようにしてみます。

frontend/src/App.tsx

...
import * as data from '../../backend/db.json';

function App(): JSX.Element {
  const [posts, setPosts] = useState<any[]>([]);

  useEffect(() => {
    const fetchApi = async () => {
      const result = data.posts;
      setPosts(result);
    };
    fetchApi();
  }, []);
...

ここまで作ったものが動いているStackBlitzはこちらです。

これでとりあえずフロントエンドをそれっぽく表示できました。

フロントエンドとバックエンドを同時に動かす

このままだと、フロントエンドがJSONファイルを読み込んでいるだけなので、バックエンドサーバーも動かしましょう。

もう1つターミナルを開いて、 npm run backend を実行すれば、バックエンドサーバーも起動します。

そして、フロントエンドからバックエンドのAPIを叩いてデータを取得するように変更します。

ドキュメントの記載は見つけられなかったのですが、サンプルから察するに、以下のURLを利用するとStackBlitz上で動くプロセス間アクセスが実現できそうです。

https://<<PROJECT_NAME>>--<<PORT>>.local.webcontainer.io

環境変数 VITE_API_URL にこのURLを設定して、フロントエンドからAPIを叩くように変更します。

frontend/.env.development

VITE_API_URL=https://rednes-react-backend-sample--8080.local.webcontainer.io

frontend/src/App.tsx

...
const API_URL = import.meta.env.VITE_API_URL || '';

function App(): JSX.Element {
  const [posts, setPosts] = useState<any[]>([]);

  useEffect(() => {
    const fetchApi = async () => {
      const response = await fetch(`${API_URL}/posts`);
      const result = await response.json();
      setPosts(result);
    };
    fetchApi();
  }, []);
...

余談ですが、このプロジェクトをStackBlitz上ではなく、ローカルマシン上で動かす場合は localhost のURLを指定すればいいです。

http://localhost:8080

なのでローカル上では .env.development.local ファイルを作って、以下のように設定しておけば、StackBlitz上でもローカルでも動かせるようになります。

frontend/.env.development.local

http://localhost:8080

このままだと、いちいちもう1つターミナルを立ち上げてバックエンドを起動する必要があります。 面倒です。

最後に、1つのターミナルでフロントエンドとバックエンドを同時に起動できるよう npm-run-all を導入します。

npm-run-all は、npm scriptsを並列実行するためのツールです。

npm-run-all --parallel <task> で指定したタスクを並列実行できます。

なので、こんな風に package.jsonnpm run dev でbackendとfrontendを並列に起動するようにすれば、StackBlitzの画面を開くと同時にフロントエンドとバックエンドが起動します。

package.json

{
  "name": "react-backend-sample",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "npm-run-all --parallel backend frontend",
    "frontend": "npm run -w frontend dev",
    "backend": "npm run -w backend dev"
  },
  "workspaces": ["backend", "frontend"],
  "devDependencies": {
    "npm-run-all": "^4.1.5"
  }
}

フロントエンド(React)とバックエンド(JSON Server)を動かしているStackBlitzがこちらです。 最初に見せたやつです。 linter(eslint, prettier)とか細かい部分もあわせて変更しています。

おわりに

StackBlitz上でReactとJSON Serverを動かして、フロントエンドからバックエンドのAPIを叩いてデータを取得するサンプルを作りました。

StackBlitz上でバックエンドも動かせるので、フロントエンドでAPIからデータを取得するサンプルを作るときに便利です。

全部ブラウザ上で完結していて、自前でAPIサーバーを用意する必要がなくなりました。 これからこの方法をフロントエンドのブログを書くときに使っていこうと思います。