コンテンツにスキップ
JP

インテグレーションAPI で作るインフラ点検マップ

更新日

インテグレーションAPI を使って、公共インフラ(マンホール・街灯・標識・ベンチ)の状態を報告する地図アプリを作ります。小さなバックエンドがインテグレーションAPI のトークンを保持し、CMS へのリクエストをすべて代行するため、トークンがブラウザに渡ることはありません。

点検担当者が地図を開き、インフラの資産をクリックして、問題の種別・深刻度・メモ・任意の写真を添えた状態レポートを送信します。レポートを送信すると、インテグレーションAPI を通じて CMS にアイテムが作成・公開され、続けてその資産自身の状態と最終点検日が更新されます。「レポート履歴を見る」ボタンから、これまで送信されたレポートを一覧できます。

アーキテクチャ図: 点検担当者がブラウザを操作し、ブラウザは /api/reports などバックエンド自身のルートだけを呼び出す。バックエンドがインテグレーションAPI を呼び出して Re:Earth CMS に到達し、ブラウザがインテグレーションAPI を直接呼び出すことはない。 Public Infrastructure Inspection Map アプリ。マンホール・街灯・標識・ベンチの4種類を色分けしたマーカーが地図上に表示され、左下に凡例がある

完成したソースコードと見比べる

  • Node.js 20 以降
  • Git
  • Re:Earth CMS のワークスペース
  • TypeScript の基礎知識

ステップ1 — CMS プロジェクトを準備する

Section titled “ステップ1 — CMS プロジェクトを準備する”

Re:Earth CMS の管理画面でプロジェクトを作成し、モデルを2つ追加します。

  1. プロジェクトの モデル 画面で 新規モデル をクリックし、名前を入力して OK をクリックします
  2. モデルの スキーマ 画面で、フィールドを追加 から型をクリックして、以下の各フィールドを追加します

infrastructure-assets — 地図に表示する資産。

フィールドキーフィールド型選択肢必須
asset-idテキスト—はい
asset-nameテキスト—はい
asset-type選択肢manhole / streetlight / traffic_sign / public_benchはい
locationジオメトリエディタポイントはい
current-condition選択肢good / fair / poor / critical / Not inspectedいいえ
last-inspected-at日付—いいえ
reference-photoアセット—いいえ
Re:Earth CMS の infrastructure-assets モデルのスキーマ画面。Asset ID・Asset Name・Asset Type・Location・Current Condition・Last Inspected At・Reference Photo の7つのフィールドが表示されている

current-condition は、資産を新規作成した時点では Not inspected が初期値として入ります。自分で設定する必要はありません。

inspection-reports — 点検担当者が送信するレポート。

フィールドキーフィールド型選択肢必須
asset-idテキスト—はい
asset-type選択肢manhole / streetlight / traffic_sign / public_benchはい
locationジオメトリエディタポイントはい
inspection-date日付—はい
condition選択肢good / fair / poor / criticalはい
issue-category選択肢no_issue / damage / obstruction / missing_component / malfunction / cleaning_required / otherはい
severity選択肢low / medium / high / urgent / not_applicableはい
notesテキストエリア—いいえ
photosアセット(複数値の設定を許可)—いいえ
report-status選択肢pending / approved / resolvedはい
Re:Earth CMS の inspection-reports モデルのスキーマ画面。Asset ID・Asset Type・Location・Inspection Date・Condition・Issue Category・Severity・Notes・Photos・Report Status の10のフィールドが表示されている

インテグレーションを作成して連携する

Section titled “インテグレーションを作成して連携する”
  1. パーソナルアカウントで マイインテグレーション を開き、新規インテグレーションを作成します — 手順の全体は インテグレーションの作成 を参照してください
  2. プロジェクトのあるワークスペースで インテグレーション を開き、作成したインテグレーションを連携します
  3. 役割を maintainer(管理者) に設定します

インテグレーションのトークンをコピーします。パスワードと同様に扱い、コミットしたり、フロントエンドのコードに書いたりしないでください。

curl でインテグレーションAPI を試す

Section titled “curl でインテグレーションAPI を試す”

アプリに触れる前に、まずリクエストを1つ直接送ってみます。ステップ3 のバックエンドのコードが組み立てているのも、これと同じ形です。<base-url>・<workspace>・<project>・<assets-model>・<token> を、それぞれ自分の値に置き換えてください。<base-url> は https://api.cms.reearth.io/api です。<workspace> と <project> は、CMS の管理画面でそのワークスペースやプロジェクトを開いているときのブラウザの URL バーに表示されています。<assets-model> は、上で infrastructure-assets を作成したときに表示された モデルキー です。<token> は、今コピーしたインテグレーションのトークンです。

Terminal window
curl -X POST \
'<base-url>/<workspace>/projects/<project>/models/<assets-model>/items' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"fields": [
{ "key": "asset-id", "type": "text", "value": "MH-001" },
{ "key": "asset-name", "type": "text", "value": "Demo Manhole 001" },
{ "key": "asset-type", "type": "select", "value": "manhole" },
{ "key": "location", "type": "geometryEditor", "value": "{\"type\":\"Point\",\"coordinates\":[138.26,36.06]}" }
]
}'

CMS は作成したアイテムを返します。次のリクエストで使う id もここに含まれています。

{
"id": "01...",
"fields": [
{ "key": "asset-id", "type": "text", "value": "MH-001" },
{ "key": "asset-name", "type": "text", "value": "Demo Manhole 001" },
{ "key": "asset-type", "type": "select", "value": "manhole" },
{ "key": "location", "type": "geometryEditor", "value": "{\"type\":\"Point\",\"coordinates\":[138.26,36.06]}" },
{ "key": "current-condition", "type": "select", "value": "Not inspected" }
],
"refs": ["latest"]
}

新規に作成したアイテムは ドラフト の状態です — refs には latest だけが入っています。アプリがステップ3 で行っているのと同じ方法で公開します。

Terminal window
curl -X POST \
'<base-url>/<workspace>/projects/<project>/models/<assets-model>/items/<item-id>/publish' \
-H 'Authorization: Bearer <token>'

refs に public が latest と並んで入るようになります — パブリックAPI からもこのアイテムを取得できる状態です。

これで資産を1件作成できました。残りは curl を繰り返す代わりに、CMS のコンソールから直接追加します — 街灯・標識・ベンチをそれぞれ用意してください。コンテンツ でモデルを選び、新規アイテム をクリックして値を入力し、保存 します。アプリは、資産が何件か存在しない限り地図に何も表示しません。

ステップ2 — リポジトリをクローンしてバックエンドを設定する

Section titled “ステップ2 — リポジトリをクローンしてバックエンドを設定する”
Terminal window
git clone https://github.com/eukarya-biz/infrastructure-inspection-tutorial.git
cd infrastructure-inspection-tutorial/backend
npm install
cp .env.example .env

Windows(コマンドプロンプト)では、cp .env.example .env の代わりに copy .env.example .env を使ってください。

.env に、ステップ1 で確認した値を入力します。

変数値
PORTバックエンドのポート番号(デフォルト 3000)
CMS_BASE_URLRe:Earth CMS の API ベース URL
CMS_WORKSPACE_IDステップ1 のワークスペース ID
CMS_PROJECT_IDステップ1 のプロジェクト ID
CMS_ASSETS_MODELinfrastructure-assets のモデルキー
CMS_REPORTS_MODELinspection-reports のモデルキー
CMS_INTEGRATION_TOKENステップ1 のインテグレーショントークン
Terminal window
npm run dev

バックエンドが http://localhost:3000 で起動します。

ステップ3 — バックエンドがインテグレーションAPI をどう使うか

Section titled “ステップ3 — バックエンドがインテグレーションAPI をどう使うか”

最初の2つのステップは、ここに来るための準備でした。このアプリが CMS に書き込む処理はすべて、.env のトークンを使ってインテグレーションAPI を呼びだす、いくつかのルートハンドラーを通ります。

backend/src/cms.ts は、CMS へのリクエストをすべて同じ形で組み立てます。プロジェクトのベース URL に、Authorization: Bearer <token> ヘッダーを添えるだけです。

export function cmsProjectUrl(config: CmsConfig, path: string): string {
return `${config.baseUrl}/${config.workspaceId}/projects/${config.projectId}${path}`;
}
export function cmsHeaders(
config: CmsConfig,
extra?: Record<string, string>,
): Record<string, string> {
return {
Authorization: `Bearer ${config.token}`,
Accept: "application/json",
...extra,
};
}

POST /api/reports(backend/src/routes/reports.ts)は fields の配列を組み立て、レポートモデルの items エンドポイントに送信します。

const fields = [
{ key: "asset-id", type: "text", value: assetId },
{ key: "asset-type", type: "select", value: assetType },
{ key: "location", type: "geometryEditor", value: JSON.stringify(location) },
{ key: "inspection-date", type: "date", value: `${inspectionDate}T00:00:00+09:00` },
{ key: "condition", type: "select", value: condition },
{ key: "issue-category", type: "select", value: issueCategory },
{ key: "severity", type: "select", value: severity },
{ key: "report-status", type: "select", value: "pending" },
];
if (validPhotoIds.length > 0) {
fields.push({ key: "photos", type: "asset", value: validPhotoIds });
}
await fetch(cmsProjectUrl(config, `/models/${modelKey}/items`), {
method: "POST",
headers: cmsHeaders(config, { "Content-Type": "application/json" }),
body: JSON.stringify({ fields }),
});

新規アイテムは ドラフト として作成されます。アプリは作成の直後、同じインテグレーションAPI のトークンを使って公開します。

await fetch(`${itemUrl}/publish`, {
method: "POST",
headers: cmsHeaders(config),
});

レポートが公開されたあと、PATCH /api/assets/:itemId(backend/src/routes/assets.ts)が資産自身の current-condition と last-inspected-at を更新し、続けて再公開してパブリックAPI 側でも変更が見えるようにします。

await fetch(itemUrl, {
method: "PATCH",
headers: cmsHeaders(config, { "Content-Type": "application/json" }),
body: JSON.stringify({
fields: [
{ key: "current-condition", type: "select", value: condition },
{ key: "last-inspected-at", type: "date", value: inspectedAt },
],
}),
});
await fetch(`${itemUrl}/publish`, {
method: "POST",
headers: cmsHeaders(config),
});

実際のハンドラーには、これらの呼び出しのまわりに検証とエラー処理が加わっています。完全なコードは backend/src/routes/reports.ts と backend/src/routes/assets.ts を参照してください。

ステップ4 — フロントエンドを動かす

Section titled “ステップ4 — フロントエンドを動かす”
Terminal window
cd ../frontend
npm install
npm run dev

http://localhost:5173 を開きます。フロントエンドはインテグレーションAPI を直接呼びだすことはなく、バックエンド自身のルート(/api/assets・/api/reports など)だけを呼び出します。それを Vite の開発サーバーがポート 3000 のバックエンドにプロキシします。トークンは終始バックエンド側にとどまります。

地図上の資産をクリックしてポップアップを開き、Start inspection をクリックしてレポートのフォームを開きます。

Demo Traffic Sign 001 のポップアップ。資産IDと現在の状態、Start inspection ボタンが表示されている New inspection report フォーム。点検日が入力され、Condition が Fair、Issue が Damage、Severity が Medium に設定され、notes 欄に曲がって植栽に覆われた標識ポールについてのメモが書かれている

フォームに入力し、Submit report をクリックします。すると、ステップ3 のバックエンドのルートが順番に呼び出されます — 写真のアップロード、レポートの作成、公開、資産の更新の順です。成功すると、地図のステータス欄に「Report submitted and <assetId> updated」と表示されます。View report history ボタンから、これまで送信されたレポート(添付した写真を含む)を一覧できます。

Report history ダイアログ。標識・街灯・ベンチの3件の点検レポートが、それぞれの状態・問題種別・深刻度・ステータス・メモとともに一覧表示され、標識のレポートには写真が添付されている

ステップ5(任意) — Re:Earth Visualizer と連携する

Section titled “ステップ5(任意) — Re:Earth Visualizer と連携する”

このステップは任意です。アプリ本体の上に乗せるおまけであり、これ以降の内容が前提とするものではありません。

2つの CMS モデルは、パブリックAPI を使えばバックエンドを介さずブラウザから直接読み取ることもできます。

  1. 各モデルの パブリックAPI 設定で 読み取り タブを開き、モデルを有効にして 変更を保存 をクリックします
  2. 各モデルの .geojson エンドポイントを確認します:https://api.cms.reearth.io/api/p/<workspace>/<project>/<model>.geojson

続いて、Re:Earth Visualizer で次の操作をします。

  1. 新規プロジェクトを作成します
  2. 各モデルについて、+新規レイヤー → リソースからレイヤーを追加 をクリックし、GeoJSON タブを選び、ソースタイプ をデフォルトの アセットから ではなく Web から に設定して、モデルの .geojson エンドポイントを リソースURL に貼り付け、レイヤーに追加 をクリックします
  3. 公開 タブを開き、公開 をクリックします

公開した URL を知っている人は誰でも、Visualizer の地図上でバックエンドが書き込んでいるのと同じインフラ資産と点検レポートを見られるようになります。

公開済みの Re:Earth Visualizer プロジェクト。パブリックAPI から直接読み取った4件のインフラ資産のマーカーが地図上に表示されている

レポートの作成で invalid value が返る

選択肢フィールドに送った値が、モデルで定義した選択肢のいずれとも一致していません。issue-category・severity など、他の選択肢フィールドの値をステップ1 のスキーマと照らし合わせてください。

地図に資産が1件も表示されない

バックエンドの .env が正しいワークスペース・プロジェクト・モデルキーを指しているか、infrastructure-assets に1件以上アイテムが存在するかを確認してください。

Visualizer に写真が表示されない

Visualizer はパブリックAPI を読み取っており、パブリックAPI は公開済みのアイテムしか返しません。レポートがドラフトのままになっていないか、公開済みかを確認してください。

  • ステップ1 で作成したインフラ資産が地図に表示される
  • 点検レポートを送信すると inspection-reports にアイテムが作成・公開される
  • レポート送信後、対象資産の状態と最終点検日が更新される
  • レポート履歴に送信済みのレポートがすべて表示される
  • (任意)Re:Earth Visualizer でも同じデータがパブリックAPI 経由で表示される