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.json | OpenAPI 3.0.3 ドキュメント(認証必要) |
GET /api/health | 匿名 readiness — DB · インメモリ · クエリログ |
GET /admin/metrics · /ping · /healthcheck · /threads | 運用メトリクス(認証必要) |
一覧にないパスは fail-closed で 401 です。匿名で開くのは / · /index.html · /api/health · 静的リソース、そして /api/v1/login の1つだけです — キーを渡す窓口であるため、キーを要求できないからです。
ヘッダー
| ヘッダー | 必須 | 値 |
|---|---|---|
X-API-Key | O | 発行されたキー、または設定のデフォルトキー |
X-Lang | O | PQL · CQL · SQL · TQL — それ以外は 400 |
X-Params | パラメータバインディング。URLエンコードされたJSONオブジェクト | |
Content-Type | O | application/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-long | epochミリ秒 → タイムスタンプ |
: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_code | HTTP | 意味 |
|---|---|---|
AUTH_MISSING | 401 | X-API-Key ヘッダーがない |
AUTH_INVALID | 401 | キーが一致しない |
PARAM_MISSING | 400 | ヘッダー · 言語 · パラメータ型変換の失敗 |
QUERY_SYNTAX | 400 | DDL拒否 · 複数文 · 構文エラー |
QUERY_DATA | 400 | データ制約違反 |
QUERY_CONSTRAINT | 409 | 整合性制約 |
QUERY_DEADLOCK | 409 | デッドロック |
QUERY_AUTH | 401 | バックエンドストレージの認証失敗 |
QUERY_CONNECTION | 503 | バックエンドに接続できない |
QUERY_TIMEOUT | 504 | バックエンド応答が遅い |
QUERY_ERROR | 500 | その他の実行失敗 |
QUERY_UNSUPPORTED | 400 | その言語がサポートしないリクエスト |
NOT_FOUND | 404 | パスなし |
METHOD_NOT_ALLOWED | 405 | メソッドなし |
UNSUPPORTED_MEDIA_TYPE | 415 | Content-Type 不一致 |
API_KEY_NOT_CONFIGURED | 503 | マスターキーが設定されていない — 資格情報の失敗ではありません |
LOGIN_NOT_CONFIGURED | 503 | コンソールアカウントの2つのキーが設定されていない |
構文 · 制約 · データ · 認証はクライアント原因(4xx) であり、接続 · タイムアウトはインフラ原因(5xx) です。1つにまとめると「自分のクエリが間違っているのか、ストレージが死んでいるのか」を呼び出し側が区別できません。サーバーログも同じ基準で 4xx は WARN、5xx は ERROR として分けて記録します。
APIキーは2つです
| 種類 | どこにあるか | 寿命 |
|---|---|---|
| デフォルトキー | 設定ファイル data.gateway.api.key(レンダリング済み) | 設定が変わるまで |
| 発行キー | POST /api/v1/keys で作成する。保存は salt + SHA-256 ダイジェストのみ | プロセス内だけに存在します — 再起動で消えます |
比較は常に定数時間で行われます。
ログインに成功すると、設定のデフォルトキーをそのまま返します。理由は ブートストラップ です — クリーンインストールではキーストアは空であり、キーを作成するすべてのパスがすでにキーを要求します。最初の入場者は、ストアより «先に» 存在する資格情報を持ってくる必要があり、それは設定ファイルのキーだけです。
そのため、このパスは キーストアを読みも書きもしません。 DBが死んでいても必ず開かれているべき扉だからです。
関連ドキュメント
- 制御と限界
- データゲートウェイ概要
- データゲートウェイクライアント — Java SDK