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

API

エンドポイント​

メソッド · パス説明
POST /api/v1/query読み取りクエリ。全結果をJSON配列で。上限に達すると truncated フラグ
POST /api/v1/query/stream同じクエリを NDJSON で — 行ごとに1行
POST /api/v1/update書き込みクエリ(TQL は拒否)
POST /api/v1/formatクエリ文のソート · インデント
POST /api/v1/cacheインメモリ現在値の1件取得
GET·POST·DELETE /api/v1/keys · /keys/{id}APIキーの一覧 · 発行 · 破棄
GET·POST /api/v1/loginコンソールログイン — /api/v1 の下でキーなしで通る唯一のパス
GET /api/v1/openapi.jsonOpenAPI 3.0.3 ドキュメント(認証必要)
GET /api/health匿名 readiness — DB · インメモリ · クエリログ
GET /admin/metrics · /ping · /healthcheck · /threads運用メトリクス(認証必要)
認証されていないパスは 401 です — 匿名ではありません

一覧にないパスは fail-closed で 401 です。匿名で開くのは / · /index.html · /api/health · 静的リソース、そして /api/v1/login の1つだけです — キーを渡す窓口であるため、キーを要求できないからです。

ヘッダー​

ヘッダー必須値
X-API-KeyO発行されたキー、または設定のデフォルトキー
X-LangOPQL · CQL · SQL · TQL — それ以外は 400
X-Paramsパラメータバインディング。URLエンコードされたJSONオブジェクト
Content-TypeOapplication/json

クエリ文は リクエストボディそのもの です。JSONで包みません。

読み取り — POST /api/v1/query​

curl -X POST -H "X-API-Key: ${PP_DATA_GATEWAY_API_KEY}" -H "X-Lang: PQL" \
-H "Content-Type: application/json" \
-d "SELECT tablename FROM pg_tables WHERE schemaname='pp'" \
https://host:5501/api/v1/query
{"result":"SUCCESS","message":"","truncated":false,
"data":[{"tablename":"mm_asset"},{"tablename":"mm_tag"}]}
truncated を無視しないでください

結果が上限(デフォルト 100,000行)に達すると、ゲートウェイは それ以上読み込まずに切断します。 truncated が true であるのにそれを見ないと、切り詰められた結果を全体と思い込んだまま集計することになります。

ストリーム — POST /api/v1/query/stream​

大きな結果はこちらです。サーバーが全体をメモリに載せず、クライアントも最初の行をすぐ受け取ります。

curl -X POST -H "X-API-Key: ${PP_DATA_GATEWAY_API_KEY}" -H "X-Lang: PQL" \
-H "Content-Type: application/json" \
-d "SELECT tablename FROM pg_tables WHERE schemaname='pp'" \
https://host:5501/api/v1/query/stream
{"row":{"tablename":"mm_asset"}}
{"row":{"tablename":"mm_tag"}}
{"end":{"count":43,"exec_ms":42,"truncated":false}}

レスポンスは application/x-ndjson で、ストリーム途中でエラーが発生した場合、最後の行は end ではなく error です。

{"error":{"message":"..."}}
end 行を必ず確認してください

認証はヘッダー段階で終わるため、このレスポンスは 常に 200 で始まります。 その後の失敗はボディ内でしか見えません — end を受け取れなかった場合は結果が終わったのではなく 接続が切れた ことであり、end.truncated が true であれば上限で切り詰められたものです。

パラメータバインディング — X-Params​

クエリ文に :이름 でプレースホルダを作り、X-Params にURLエンコードされたJSONオブジェクトを入れます。

PARAMS=$(python3 -c "import urllib.parse,json;print(urllib.parse.quote(json.dumps({
'site_id': 'SITE_00001',
'from:ts-long': 1772041960266,
'limit:int': 500
})))")

curl -X POST -H "X-API-Key: ${PP_DATA_GATEWAY_API_KEY}" -H "X-Lang: PQL" \
-H "X-Params: ${PARAMS}" -H "Content-Type: application/json" \
-d "SELECT * FROM pp.mm_tag WHERE site_id = :site_id AND created_at >= :from LIMIT :limit" \
https://host:5501/api/v1/query

キーに :타입 を付けて変換を指定します。付けなければJSONの型のまま入ります。

接尾辞意味
:int · :long · :float · :double数値
:string文字列
:epoch · :ts-longepochミリ秒 → タイムスタンプ
:ts-string日付文字列 → タイムスタンプ

不明な型接尾辞は 400 PARAM_MISSING です — 黙って無視しません。

X-Params が壊れていると 400 であり 500 ではありません

デコードできない値(%zz)やJSONでない値は クライアントエラー です。以前はこれが 500 INTERNAL_ERROR として漏れ出し、「サーバーが故障した」と解釈されていました。

書き込み — POST /api/v1/update​

curl -X POST -H "X-API-Key: ${PP_DATA_GATEWAY_API_KEY}" -H "X-Lang: PQL" \
-H "Content-Type: application/json" \
-d "UPDATE pp.mm_tag SET description = 'reactor inlet' WHERE tag_id = 'TAG_001'" \
https://host:5501/api/v1/update

TQL はこのパスで拒否されます — 時系列エンジンはゲートウェイ経由の書き込みを受け付けません。

エラー契約​

すべてのエラーが同じエンベロープで返されます。

{"result":"ERROR","error_code":"QUERY_SYNTAX",
"message":"DDL statements are not allowed: DROP"}
error_codeHTTP意味
AUTH_MISSING401X-API-Key ヘッダーがない
AUTH_INVALID401キーが一致しない
PARAM_MISSING400ヘッダー · 言語 · パラメータ型変換の失敗
QUERY_SYNTAX400DDL拒否 · 複数文 · 構文エラー
QUERY_DATA400データ制約違反
QUERY_CONSTRAINT409整合性制約
QUERY_DEADLOCK409デッドロック
QUERY_AUTH401バックエンドストレージの認証失敗
QUERY_CONNECTION503バックエンドに接続できない
QUERY_TIMEOUT504バックエンド応答が遅い
QUERY_ERROR500その他の実行失敗
QUERY_UNSUPPORTED400その言語がサポートしないリクエスト
NOT_FOUND404パスなし
METHOD_NOT_ALLOWED405メソッドなし
UNSUPPORTED_MEDIA_TYPE415Content-Type 不一致
API_KEY_NOT_CONFIGURED503マスターキーが設定されていない — 資格情報の失敗ではありません
LOGIN_NOT_CONFIGURED503コンソールアカウントの2つのキーが設定されていない
4xx と 5xx を分けたことが核心です

構文 · 制約 · データ · 認証はクライアント原因(4xx) であり、接続 · タイムアウトはインフラ原因(5xx) です。1つにまとめると「自分のクエリが間違っているのか、ストレージが死んでいるのか」を呼び出し側が区別できません。サーバーログも同じ基準で 4xx は WARN、5xx は ERROR として分けて記録します。

APIキーは2つです​

種類どこにあるか寿命
デフォルトキー設定ファイル data.gateway.api.key(レンダリング済み)設定が変わるまで
発行キーPOST /api/v1/keys で作成する。保存は salt + SHA-256 ダイジェストのみプロセス内だけに存在します — 再起動で消えます

比較は常に定数時間で行われます。

コンソールログインは «キーを発行» しません

ログインに成功すると、設定のデフォルトキーをそのまま返します。理由は ブートストラップ です — クリーンインストールではキーストアは空であり、キーを作成するすべてのパスがすでにキーを要求します。最初の入場者は、ストアより «先に» 存在する資格情報を持ってくる必要があり、それは設定ファイルのキーだけです。

そのため、このパスは キーストアを読みも書きもしません。 DBが死んでいても必ず開かれているべき扉だからです。

関連ドキュメント​