Skip to content

API-005 外部データ取込 REST ​

← API-一覧

概要 ​

min-repo HTML インポート(ADM-011)と ana-slo データ取得(ADM-020)の「HTML 貼り付け → 機種名の紐付け確認 → 取込」を、管理画面を開かずに行うための REST。取込担当ロール(min_repo_importer)のユーザーがアプリケーションパスワードで呼ぶ。名前空間は data-import/v1。

処理は両画面と同じ DailyDataHtmlImportService を通す(HTML 検証・パース、紐付けの保存、db2023 への取込、取込履歴の記録)。画面で取り込んだ場合と REST で取り込んだ場合で、保存される紐付けと取り込まれる行は同じになる。

{source} は min-repo または ana-slo(DataImportSourceEnum)。取込元ごとに固定のルート(/min-repo/preview 等)を登録し、権限判定と処理はルートの取込元で行う。取込元ごとに取り込めるホールが決まっている。

source取り込めるホール(hall)必要な Capability
min-repoisland / espasuimport_min_repo_html
ana-sloisland / espasu / bigappleimport_ana_slo_html

共通入力(preview / import) ​

JSON ボディ。

param必須型・制約説明
sourceいいえルートの取込元と同じ値省略可。指定するときはルートの {source} と同じ値にする(違えば 400)
html条件string(5MB 以下)取込元ページの HTML。html_base64 とどちらか一方
html_base64条件Base64(デコード後 5MB 以下)HTML を Base64 にしたもの。WAF が HTML 本文を弾く環境向け。空白・改行は無視する
dateはいYYYY-MM-DD(実在する日付)データの日付
hallはい上表のホールキー取込先ホール
mappingsいいえarray(500 件以下)機種名の紐付け指定。各行は kishu_name(255 文字以内。前後の空白を除いた文字列で HTML 上の機種名と照合)と、master_id(既存マスタ ID)または new_name(新しい機種マスタ名)のどちらか一方

5MB の上限は DailyDataHtmlImportConstants::MAX_HTML_LENGTH(画面と共通)。

紐付けの決まり方 ​

HTML 上の機種名ごとに、次の順で紐付け先を決める。画面の紐付け確認フォームで「現在の紐付けのまま確定」するのと同じ結果になる。

  1. mappings に master_id があればその既存マスタ
  2. mappings に new_name があればその名前の機種マスタ(同名が未登録なら新規登録)
  3. すでに紐付いていればその機種マスタ
  4. どれでもなければ未紐付け(unmapped)

mappings の kishu_name が HTML に無い機種名のときは 400(unknown に列挙)。

API-005-1 POST /{source}/preview ​

HTML を検証・パースし、機種ごとの紐付け状況を返す。DB には書かない。

入力(リクエスト) ​

共通入力に加えて次を受け付ける。

param必須型・制約説明
include_mastersいいえbooltrue のとき紐付け候補の機種マスタ一覧を masters に含める

出力(レスポンス) ​

field型説明
successbooltrue
sourcestring取込元
datestring日付
hallstringホールキー
row_countintパースした行数
ready_to_importbool未紐付けの機種が無く、同じ入力で import できるか
unmappedstring[]mappings を反映しても未紐付けの機種名
itemsarray機種名ごとの現在の紐付け { kishu_name, status, kishu_id, master_name, master_inactive, suggested_name }[]。status は画面の紐付け確認と同じ
mastersarrayinclude_masters 指定時のみ。{ id: int, name: string }[]

HTTP ステータス: 200

API-005-2 POST /{source}/import ​

紐付けを保存して db2023 に取り込み、取込履歴に記録する。

入力(リクエスト) ​

共通入力に加えて次を受け付ける。

param必須型・制約説明
delete_existingいいえbooltrue のとき同じ日付・ホールの既存データを削除してから取り込む(省略時 false)

出力(レスポンス) ​

field型説明
successbooltrue
messagestringDataImportRestCopy::IMPORT_SUCCESS
sourcestring取込元
datestring日付
hallstringホールキー
success_countint取り込んだ行数
deleted_countint削除した既存行数
delete_existingbool既存データを削除したか
new_name_countintnew_name で紐付けた機種の数

HTTP ステータス: 200

同じ date・hall の取込が実行中のときは 409 を返す。ロックは DailyDataHtmlImportService が取るため、取込元をまたいで、また管理画面(ADM-011 / ADM-020)の取込とも排他になる(両取込元とも同じ db2023 の行に書くため)。Service は OptionRowLockInterface に依存し、実装の WordPressOptionRowLock が wp_options に所有トークン付きの行(_option_row_lock_<md5>、autoload しない)を 1 つ入れて取る。異常終了しても 300 秒経てば次の取込が引き継ぐ。DB エラーでロックを取れなかったときは 503(Messages::DAILY_DATA_IMPORT_LOCK_UNAVAILABLE)を返し、error_log に [option-row-lock] acquire failed: db error を 1 行書く。

ロックの有効期間(DailyDataHtmlImportService::IMPORT_LOCK_TTL_SECONDS = 300 秒)は PHP の max_execution_time より長くしておく。短いと、取込中に期限が切れて同じ日付・ホールの取込が重なり得る。MCP の import はクライアント側で 180 秒で打ち切るが、サーバー側の取込は止まらずロックも持ったままになる。打ち切り後すぐに再実行すると 409 になるので、latest-day や history で結果を確かめてから再実行する。致命的エラーや実行時間超過で解放されなかったロック行は、同じ日付・ホールを取り込まない限り wp_options に残る。期限切れの行は daily WP-Cron が読んだ値と一致する場合だけ消す(保守クリーンアップバッチ)。

API-005-3 GET /{source}/latest-day ​

ホールの db2023 最新日と、その翌日(次に取り込む想定の日付)を返す。ADM-020 の日付ズレ確認と同じ値。

入力(リクエスト) ​

param必須型・制約説明
hallはい上表のホールキー対象ホール

出力(レスポンス) ​

field型説明
successbooltrue
sourcestring取込元
hallstringホールキー
latest_daystring/nulldb2023 の最新日(YYYY-MM-DD)。無ければ null
expected_next_daystring/null最新日の翌日。無ければ null

HTTP ステータス: 200

API-005-4 GET /history ​

取込履歴(画面・REST の両方、min-repo / ana-slo の両方)を新しい順に返す。

入力(リクエスト) ​

param必須型・制約説明
limitいいえ1〜50件数(省略時 20)
sourceいいえmin-repo / ana-slo指定した取込元だけに絞る

出力(レスポンス) ​

field型説明
successbooltrue
itemsarray{ source, date, hall_keys, imported_at, row_count, user_id }[]。source が無い旧形式の履歴は min-repo、user_id は null

HTTP ステータス: 200

失敗・エラー条件 ​

失敗時のボディは { success: false, message }。message は固定文言だけを返し、例外メッセージや HTML は載せない。

条件HTTPmessage
ボディ・クエリの source がルートの取込元と違う400DataImportRestCopy::SOURCE_MISMATCH
source 不正(history)400DataImportRestCopy::SOURCE_INVALID
html / html_base64 が無い・両方ある400DataImportRestCopy::HTML_REQUIRED
html_base64 をデコードできない400DataImportRestCopy::HTML_BASE64_INVALID
HTML が 5MB を超える400DataImportRestCopy::HTML_TOO_LONG
date 不正400DataImportRestCopy::DATE_INVALID
hall がその取込元で取り込めない400DataImportRestCopy::HALL_INVALID
delete_existing が bool として読めない400DataImportRestCopy::DELETE_EXISTING_INVALID
mappings の形式不正400DataImportRestCopy::MAPPINGS_INVALID
mappings が 500 件を超える400DataImportRestCopy::MAPPINGS_TOO_MANY
mappings に HTML に無い機種名がある400DataImportRestCopy::MAPPINGS_UNKNOWN(unknown 付き)
HTML が取込元のページとして検証できない(min-repo)400DataImportRestCopy::HTML_INVALID(errors 付き)
HTML からデータ行を取り出せない400画面と同じパース失敗文言
紐付けの保存に失敗(master_id が無効等)400DataImportRestCopy::MAPPING_SAVE_FAILED
limit 不正400DataImportRestCopy::LIMIT_INVALID
権限が無い403WordPress REST 標準の 403
同じ日付・ホールの取込が実行中(画面の取込も含む)409Messages::DAILY_DATA_IMPORT_LOCKED
DB エラーで取込ロックを取れない503Messages::DAILY_DATA_IMPORT_LOCK_UNAVAILABLE
未紐付けの機種が残っている(import)422DataImportRestCopy::UNMAPPED_EXISTS(unmapped 付き)
レート制限を超えた429Messages::RATE_LIMIT_EXCEEDED
db2023 への取込に失敗500DataImportRestCopy::IMPORT_FAILED
最新日の取得に失敗500DataImportRestCopy::LATEST_DAY_FAILED
preview / import の検証・パース中の予期しない例外500DataImportRestCopy::UNEXPECTED_ERROR

レート制限 ​

ユーザーごとの固定ウィンドウ(60 秒)。BotRestRateLimiter(transient)で数える。

対象上限カウンタを保存できないとき
import10 回 / 分拒否(429)
preview30 回 / 分通す
latest-day / history(共通)60 回 / 分通す

監査ログ ​

preview と import は BotRestAuditLogger で error_log に 1 行 JSON(接頭辞 [bot-rest-audit])を書く。記録するのはルート・ユーザー ID・取込元・日付・ホール・行数・結果(outcome)・件数だけで、HTML 本文と機種名の一覧は書かない(配列は件数に置き換える)。予期しない例外は outcome: error とし、例外の内容はレスポンスに載せず error_log にだけ書く。

権限・nonce ​

全エンドポイント共通。DataImportRestHandler + WordPressDataImportPermissionChecker。{source} のあるルートはルートの取込元の Capability を(ボディ・クエリの source では判定しない)、/history はどちらか一方の Capability を求める。権限が無いときは WordPress REST 標準の 403。アプリケーションパスワード(Basic 認証)で呼ぶ前提のため nonce は検証しない。Local バイパスの条件は WordPressPermissionChecker と同じ。