メインコンテンツまでスキップ

REST API (v1)

PlantPulse Edge の v1 REST API マニュアルです。画面 / 外部システムが OPC、タグ、モニタリング、外部転送ヘルスチェックを扱うための標準インターフェースです。

項目
Base URLhttp(s)://<edge-host>/api/v1
Content-Typeapplication/json; charset=utf-8
認証API Key 強制 (edge.rest.api.auth=true) — X-API-Key / Authorization: Bearer、またはログインセッションで通過。?api_key= は 401 で拒否
Audit ログApiAccessLogFilter — すべての /api/* 呼び出しを1行で記録 (メソッド/パス/ステータス/所要時間/IP/ユーザー/auth モード)
メインコントローラplantpulse.app.edge.api.v1.* (OpcAPI, TagAPI, AppAPI, SystemAPI, MonitoringAPI)
エラー envelope{data, meta, errors} — filter/advice 経路も同一
HTTPSedge.rest.api.https_only=true が既定。plain HTTP クライアント呼び出しは拒否、または Tomcat の HTTPS リダイレクトポリシーに従う

認証 (ApiAuthFilter)

app.properties にて edge.rest.api.auth=true で有効化します。キーは edge.rest.api.key であり、運用環境では EDGE_REST_API_KEY_FILE または EDGE_REST_API_KEY で注入します。

次の3つのうち いずれか1つでも 満たせば通過します。

A. ログインセッションによる通過 (ブラウザ)

すでに /login/form でログインしているユーザー — セッションに _USER_LOGIN attribute (JSONObject) があれば ApiAuthFilter がそのまま chain.doFilter() します。画面 (JSP) から ajax で呼び出すすべての /api/* が追加キーなしで動作します。

B. X-API-Key ヘッダー (推奨)

EDGE_REST_API_KEY="$(tr -d '\r\n' < /run/secrets/edge-rest-api-key)"
cfg="$(mktemp)"
trap 'rm -f "$cfg"' EXIT
printf 'header = "X-API-Key: %s"\n' "$EDGE_REST_API_KEY" > "$cfg"
curl --config "$cfg" https://edge.example.com/api/v1/tag/TAG_LS_XBC_0001/value

C. Authorization: Bearer <key> ヘッダー

EDGE_REST_API_KEY="$(tr -d '\r\n' < /run/secrets/edge-rest-api-key)"
cfg="$(mktemp)"
trap 'rm -f "$cfg"' EXIT
printf 'header = "Authorization: Bearer %s"\n' "$EDGE_REST_API_KEY" > "$cfg"
curl --config "$cfg" https://edge.example.com/api/v1/tag/TAG_LS_XBC_0001/value

D. ?api_key=<key> クエリパラメータ — 拒否されます

URL にキーが平文で入り、アクセスログ/プロキシキャッシュ/ブラウザ履歴に残る可能性があるため、 v1 では 401 で拒否します。ヘッダー方式 (B/C) を使用してください。

失敗レスポンス

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8

{
"data": null,
"meta": {
"timestamp": 1778069486934,
"status": "ERROR",
"http_status": 401,
"request_id": "3b89b8f1-0fc1-4ab4-b4eb-d12dc314d500"
},
"errors": [
{
"code": "UNAUTHORIZED",
"message": "Invalid or missing X-API-Key."
}
]
}

キーの比較は constantTimeEquals() (タイミング攻撃対策)。

edge.rest.api.auth=false (開発 / 一時利用)

認証を無効にすると ApiAuthFilter は直ちに chain.doFilter() — 外部からキーなしで呼び出せます。運用ネットワークでは常に true を推奨します。


Audit ログ (ApiAccessLogFilter)

すべての /api/* 呼び出しを1行のログとして記録します — 認証失敗 (401) も含め、audit トレイルを残します (フィルタチェーン順: ApiAccessLogFilter → ApiAuthFilter)。

形式

[API_ACCESS] method=GET path=/api/v1/tag/TAG_MS_1000/value query= status=200 duration=12ms
ip=100.127.147.98 user=admin auth=session ua=Mozilla/5.0...
フィールド意味
methodHTTP メソッド
pathrequest URI (クエリを含まない)
queryクエリ文字列 — 拒否される ?api_key=... 部分も *** でマスキング
statusHTTP レスポンスコード
duration処理時間 (ms)
ip既定は RemoteAddredge.rest.api.trust_x_forwarded_for=true のリバースプロキシ構成でのみ X-Forwarded-For の先頭 IP
usersession ユーザーなら user_id / apikey なら XXXX*** (len=16) (先頭4文字 + 長さ) / 匿名なら -
authsession (ブラウザログイン) / apikey (X-API-Key/Bearer) / deprecated_query (拒否された ?api_key= の試行) / none (キー欠落または匿名)
uaUser-Agent (80文字を超える場合は で切り詰め)
error例外発生時に error=ClassName を追加

ログレベルの分岐

ステータスレベル意図
5xx または throwableERRORサーバーエラー — 即時アラーム
401, 403WARN認証/権限拒否 — audit 優先
その他 (2xx, 3xx, 一般的な 4xx)INFO通常の呼び出し

活用

  • 誰がキーを誤って送信しているかgrep '\[API_ACCESS\].*status=401' で 401 トレイルを確認
  • 5xx リグレッションの追跡grep '\[API_ACCESS\].*status=5' + error= フィールド
  • 呼び出し頻度 / ユーザー別集計 — auth=apikey/session でグルーピングし、ip 別に分析
  • レスポンス遅延・スロークエリduration= が大きい行を抽出

キーの平文は どこにも ログに残りません — query のマスキング + user フィールドの先頭4文字のみで識別します。侵害インシデント分析 に十分な識別性と平文露出防止のバランスです。

フィルタチェーンの順序が重要

web.xml のマッピング順序: ApiAccessLogFilter が先、その次に ApiAuthFilter。AccessLog が finally ブロックで status を記録するため、認証に失敗した 401 呼び出しもそのまま audit されます。順序が逆になると、401 呼び出しが access log から欠落します。


レスポンス envelope

v1 REST API のレスポンスは共通 envelope でラップされます (RestApiSupport, ApiEnvelopeWriter)。

正常レスポンス:

{
"data": { },
"meta": {
"timestamp": 1778069486934,
"status": "OK",
"request_id": "f818abd0-eb0f-4497-9b07-7ccc94b2e2d7"
}
}

エラーレスポンス:

{
"data": null,
"meta": {
"timestamp": 1778069486934,
"status": "ERROR",
"http_status": 400,
"request_id": "3b89b8f1-0fc1-4ab4-b4eb-d12dc314d500"
},
"errors": [
{
"code": "VALIDATION_FAILED",
"message": "Validation failed"
}
]
}

旧 RPC-style envelope (result, _session_id, _user_id) は REST v1 では使用しません。


1. エンドポイント一覧

1.1 OPC

スラグMethodURL説明
flow_edge_opc_listGET/api/v1/opcOPC 一覧 (tag_count / connection_status / scan_status を含む)
flow_edge_opc_createPOST/api/v1/opcOPC + タグの一括登録
flow_edge_opc_updatePUT/api/v1/opc/{opcId}OPC + タグの一括更新 (path の opcId が body の opc_id を上書き)
flow_edge_opc_deleteDELETE/api/v1/opc/{opcId}OPC および配下タグの一括削除
flow_edge_opc_startPOST/api/v1/opc/{opcId}/start収集開始
flow_edge_opc_stopPOST/api/v1/opc/{opcId}/stop収集停止

1.2 Tag

スラグMethodURL説明
flow_edge_tag_listGET/api/v1/opc/{opcId}/tag特定 OPC のタグ一覧 (最終値/状態を含む)
flow_edge_tag_createPOST/api/v1/opc/{opcId}/tagタグ単体の登録
flow_edge_tag_updatePUT/api/v1/tag/{tagId}タグ単体の部分更新 (既存 row をマージ後 upsert)
flow_edge_tag_deleteDELETE/api/v1/tag/{tagId}タグ単体の削除
flow_edge_tag_readGET/api/v1/tag/{tagId}/value[?fresh=true]キャッシュ値 (default)、fresh=true の場合は PLC から直接 read
flow_edge_tag_writePOST/api/v1/tag/{tagId}/value値の書き込み — 全プロトコル対応 (HTTP / OPC-UA / Modbus / MELSEC / S7 / LS / EIP)

1.3 Monitoring / Edge / Transfer

スラグMethodURL説明
flow_edge_monitoringGET/api/v1/monitoringCPU/メモリ/ネットワーク/ディスク/スレッドなど MonitorBean の全フィールド
flow_edge_infoGET/api/v1/edgeエッジの識別/バージョン/サイト/OS/稼働時間メタ
flow_edge_transferGET/api/v1/transferoutbound transfer (API/MQTT/Sparkplug) ごとのヘルス状態

1.3a System (認証不要 — LB / k8s probe / OTA 用)

/api/v1/system/* のうち以下の3つは ApiAuthFilter ホワイトリストを通過します (OPC/Tag 情報は一切公開しません)。

MethodURL説明HTTP
GET/api/v1/system/health8コンポーネント (cassandra / redis / mqtt / node_red / opc_ua / edge_core / tse / grafana) の TCP 200ms probe + 総合 status200 (all UP) / 503 (DEGRADED)
GET/api/v1/system/readymonitor + V5 api_client の準備状態200 / 503
GET/api/v1/system/versionMetadata.VERSION + BUILD_DATE + /etc/kopens/version.env image_tag + /.dockerenv container_mode200

/health の例:

{
"data": {
"status": "UP",
"uptime_ms": 1720008,
"components": {
"cassandra": "UP", "redis": "UP", "mqtt": "UP",
"node_red": "UP", "opc_ua": "UP"
}
}
}

/version の例:

{
"data": {
"product_name": "PlantPulse Edge",
"version": "2026",
"build_date": "20260523",
"image_tag": "2026-20260523",
"container_mode": true
},
"meta": {
"timestamp": 1778925572946,
"request_id": "..."
}
}

OTA upgrade.sh/api/health (300秒) の probe で auto-rollback を判断します。Docker HEALTHCHECK も /health を使用します。

1.4 OPC-UA ビューア (OPCUAViewerAPI)

内蔵 OPC-UA サーバーの endpoint / ノードツリー / 時系列 — /ui/opcua 画面が使用します。

MethodURL説明
GET/ui/opcua/info[?reveal=true]内蔵 OPC-UA サーバーの endpoint URL (TCP/TLS) / Application 名 / 認証情報 (reveal=true + 認証済みセッション時は password 平文)
GET/ui/opcua/treeSite → OPC → Tag ツリー (NodeId 含む)。EDGE_* のシステム OPC は常に connection_status=CONNECTED
GET/ui/opcua/history?tagId=...&minutes=N&limit=MCassandra tm_tag_point の時系列照会。入力検証後、ASC ソートされた points 配列を返す

1.5 アップグレード / システム (ConfigAPI)

/config/* は v1 REST API とは別 (管理者画面用) ですが、本マニュアルで併せて整理します。

MethodURL説明
GET/config/upgrade/checkserver-to-server で product.kopens.io の VERSION.JSON を取得し {result, latest_version, latest_build_date} を返す。失敗時は result=ERROR
POST/config/upgradebin/upgrade.sh を実行 (長時間処理)
POST/config/restartbin/restart.sh を実行 (Tomcat 再起動)
POST/config/rebootbin/reboot.sh を実行 (OS 再起動)
POST/config/temp-cleanbin/clean.sh を実行 (ログ/一時ファイル整理)
POST/config/backupbin/backup.sh を実行
POST/config/firmwarebin/firmware.sh を実行 (dnf update -y)
GET/config/loadapp.properties のテキストを返す
POST/config/saveapp.properties を保存

2. リクエスト / レスポンス例

2.1 GET /api/v1/opc — OPC 一覧

curl -s http://<edge-host>/api/v1/opc | jq
{
"result": "OK",
"data": {
"data": [
{
"opc_id": "OPC_UA_Kepware",
"opc_type": "OPCUA",
"opc_name": "OPC_UA_Kepware",
"opc_agent_ip": "192.168.0.40",
"opc_agent_port": "49320",
"auto_collect": "true",
"timecycle": "1000",
"options": {"username": "kopens", "password": "***", "discovery": "false"},
"tag_count": 11,
"point_count": 5819,
"connection_status": "CONNECTED",
"scan_status": "START"
}
]
}
}

data.data[] の形式 (二重ラップ) — 上記 envelope セクションを参照。

2.2 POST /api/v1/opc — OPC + タグの一括登録

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_NEW",
"opc_type": "OPCUA",
"opc_name": "신규 연결",
"opc_agent_ip": "10.0.0.10",
"opc_agent_port": "49320",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"tag_list": [
{"tag_id": "TAG_001", "tag_name": "Sine",
"plc_address": "ns=2;s=Sine1", "data_type": "Float"}
]
}'

2.3 POST /api/v1/opc/{opcId}/tag — タグ単体の登録

{
"tag_id": "TAG_NEW",
"tag_name": "신규 태그",
"plc_address": "ns=2;s=NewTag",
"data_type": "Float",
"description": "..."
}

レスポンス:

{ "result": "OK", "data": { "result": "SUCCESS", "tag_id": "TAG_NEW" } }

site_id は OPC から自動的に補完されます。

2.4 PUT /api/v1/tag/{tagId} — タグの部分更新

リクエスト body には変更するフィールドのみを送ります。サーバー側で既存 row とマージ後 upsert します。

{ "description": "변경된 설명" }

2.5 GET /api/v1/tag/{tagId}/value — 最終値の照会

既定 (キャッシュ):

curl -s http://<edge-host>/api/v1/tag/TAG_UA_0004/value | jq
{
"result": "OK",
"data": {
"tag_id": "TAG_UA_0004",
"value": "28.9688",
"value_time": "2026-05-06 20:59:39.000",
"value_read_status": "SUCCESS",
"value_read_error_message": ""
}
}

fresh=true (PLC から直接 read):

curl -s 'http://<edge-host>/api/v1/tag/TAG_UA_0004/value?fresh=true' | jq

PLC read 失敗時は外部 result=ERROR + message:

{ "result": "ERROR", "message": "fresh read failed: ..." }

⚠ 存在しないタグを照会しても envelope は result=OK で応答し、value"-" で埋められた placeholder ペイロードを返します (現在の動作)。

2.6 POST /api/v1/tag/{tagId}/value — 値の書き込み

curl -X POST http://<edge-host>/api/v1/tag/TAG_HTTP_001/value \
-H "Content-Type: application/json" \
-d '{ "value": "42" }'

成功:

{
"result": "OK",
"data": {
"result": "SUCCESS",
"opc_id": "OPC_LS_TEST",
"plc_address": "D1000",
"value": "42",
"actual_read": "42"
}
}

失敗 (ドライバが false を返す / OPC DISCONNECTED / スケジューラ未稼働) — 外部 envelope result=ERROR:

{ "result": "ERROR", "message": "쓰기 실패 (opc_type=EIP) — EIP 펌웨어/패치에 따라 ..." }

対応プロトコル: HTTP / OPC-UA / Modbus / MELSEC / S7 / LS XGT / EIP — すべて可能。EIP は PLC のファームウェア/パッチにより制約が生じる場合があります。

2.7 POST /api/v1/opc/{opcId}/start — 収集開始

curl -X POST http://<edge-host>/api/v1/opc/OPC_NEW/start

内蔵 OPCUA/MODBUS シミュレータの自動起動は未対応です。テスト/デモデータには外部 plantpulse-simulator またはテストタグを使用してください。

2.8 GET /api/v1/edge — エッジ識別 / 稼働情報

EdgeAPI.edgeInfo() が直接埋めるフィールド:

{
"result": "OK",
"data": {
"id": "EDGE_00303",
"site_id": "SITE_00001",
"site_name": "S1_LOTTE_CS_DJ_SITE",
"hostname": "EDGE-303",
"product_name": "PlantPulse Edge",
"version": "2026",
"build_date": "2026-05-08",
"os_name": "Linux",
"os_version": "6.14.5-100.fc40.x86_64",
"os_arch": "amd64",
"started": true,
"started_date": 1778066700000,
"uptime_ms": 124500,
"always_on": false,
"ttl": 30,
"sended_count": 8063
}
}

2.9 GET /api/v1/monitoring — システムメトリクス

MonitorBean の全フィールドをそのままシリアライズします。1秒周期で更新。

curl -s http://<edge-host>/api/v1/monitoring | jq '.data | keys'

主なフィールド: cpu_used_percent, memory_used_percent, disk_used_percent, temperature, ping, api, opc_count, tag_count, mps, mps_history, queue_size, plc_value_read_success_count, plc_value_read_error_count, plc_value_write_success_count, plc_value_write_error_count, plc_con_connected_count, plc_con_disconnected_count, plc_scan_start_count, plc_scan_not_collect_count, plc_scan_stop_count, sended_point_count, sended_point_bytes, system_total_db_size, system_error_count, docker_on, docker_container_up_count, docker_container_total_count

2.10 GET /api/v1/transfer — 外部転送ヘルス

curl -s http://<edge-host>/api/v1/transfer | jq
{
"result": "OK",
"data": {
"transfers": [
{ "type": "API", "enabled": true, "connected": true, "sent_count": 8063 },
{ "type": "MQTT", "enabled": true, "connected": true, "sent_count": 12345 },
{ "type": "Sparkplug", "enabled": true, "connected": true,
"group_id": "Plant1", "edge_node_id": "EDGE_00303",
"bdSeq": 7, "seq": 211 }
]
}
}

各 transfer の getStatus() 結果をそのまま配列で返します。呼び出し中に例外が発生した場合は {type, status_error} にフォールバックします。

2.11 GET /ui/opcua/info — 内蔵 OPC-UA サーバー情報

curl -s http://<edge-host>/ui/opcua/info | jq
{
"result": "OK",
"data": {
"application_name": "PlantPulse Edge OPC-UA Server",
"product_uri": "urn:plantpulse:opcua:server",
"domain": "127.0.0.1",
"tcp_endpoint": "opc.tcp://127.0.0.1:12000",
"tls_endpoint": "opc.tcp://127.0.0.1:12443",
"namespace_index": 2,
"auth_username": "edge",
"auth_password_set": true,
"auth_anonymous": false
}
}

?reveal=true かつ認証済みセッションの場合は auth_password の平文を追加します。

2.12 GET /ui/opcua/tree — ノードツリー

Site → OPC → Tag の3階層ツリー。各タグに NodeId、最新値、データ型、description を含みます。EDGE システム OPC は connection_status=CONNECTED を強制します。

NodeId の規約: ns=2;s=<SITE>.<OPC>.<TAG>

2.13 GET /ui/opcua/history — 時系列

パラメータ既定制限
tagId必須最大200文字
minutes101 – 1440 (24h)
limit6001 – 5000
curl -s 'http://<edge-host>/ui/opcua/history?tagId=TAG_S7_1000&minutes=10&limit=100' | jq
{
"result": "OK",
"data": {
"tag_id": "TAG_S7_1000",
"minutes": 10,
"count": 100,
"points": [
{ "ts": 1778176880010, "value": "211", "type": "integer", "quality": 192 }
]
}
}

tagId の欠落/空白/200文字超過時は外部 result=ERROR (message)。Cassandra の timestamp が wrap オブジェクトで来た場合も extractTimestampMs で epoch ms に変換します。


3. エラーレスポンスのパターン

ケースレスポンス形式
外部 envelope ERROR (write 失敗 / fresh read 失敗 / opcua/history の入力検証失敗 / upgrade/check のダウンロード失敗){result:"ERROR", message:"..."} (HTTP 200)
内部業務 ERROR (CRUD 時の tag/opc not found / DB 整合性 / スケジューラ未稼働){result:"OK", data:{result:"ERROR", msg:"..."}} (HTTP 200)
Spring のマッピング不一致 (必須パラメータ欠落、メソッド誤りなど)HTTP 500 + スタックトレース — 推奨: コントローラ層で @RequestParam(required=false) を処理し envelope に変換
認証 — edge.rest.api.auth はインストール既定値が true であり、ApiAuthFilterX-API-Key / Bearer を要求します (上記の認証節を参照)。ヘルスエンドポイントのみ例外

4. 動作メモ

  • タグ単体の照会: APP_TAG.xmlR03 (WHERE TAG_ID = :tag_id ALLOW FILTERING)。
  • OPC + タグの一括登録 / タグ単体の登録 後に ConnectService.restartComponents() を呼び出し → OPCAndTagsCache の reload および OPC-UA サーバーの再起動。
  • 値の書き込み (tagWriteByTagId): HTTP は HTTPDriver.bind()、それ以外は driver.write(ProtocolAddress)。失敗時 (ok=false) には親切なヒント (EIP ファームウェア互換性など) を含みます。write 後に即座に read した結果を actual_read として併せて返します (HTTP を除く)。
  • トランスファーヘルス (/api/v1/transfer): TransferRegistry に登録されたすべての outbound コンポーネントの getStatus() を集約します。Sparkplug B カード (/ui/main) が5秒周期で呼び出します。
  • OPC-UA ビューア (/ui/opcua/*) は内部網ポーリング (2秒) — OPCAndTagsCache.getInstance() + LastValueMap.getInstance() のみを使用するため負荷は小さいです。
  • レガシー deprecated: /api/http (APIController) — /api/v1/tag/{tagId}/value の使用を推奨。

5. コードの場所

  • コントローラ: src/plantpulse/app/edge/api/v1/OpcAPI.java · api/v1/TagAPI.java
  • OPC-UA ビューア: src/plantpulse/app/edge/module/opcua/OPCUAViewerController.java
  • アップグレードプロキシ: src/plantpulse/app/edge/module/system/config/ConfigController.java
  • ビジネスロジック: src/plantpulse/app/edge/module/connect/ConnectService.java
  • レスポンス envelope helper: plantpulse.app.edge.core.web.ControllerSupport (ok() / error())