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

1. はじめに

V5 Java APIクライアントを使用して、最初のコールを送信するまでの手順を案内します。

クイックスタート (60秒)​

必要な3つの項目

項目値場所
サーバーアドレスhttp://<server-ip>:80 (TLSは https://<server-ip>:443)REST API エンドポイント。ウェブコンソールと同じアドレスです
アカウントID例: apiAPIコール用ユーザーアカウント
トークンUUID形式コンソール セキュリティ管理 → API認証トークン(/token/index) でそのアカウントとして発行 → セキュリティ設定 · セキュリティ管理

これら3つの値があれば、以下のブロックひとつで最初のコールが可能です。

import java.util.List;
import plantpulse.api.v5.APIClient_V5;
import plantpulse.api.v5.dto.response.SiteResponseV5;

try (APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api", "<issued-token>", false)) {
client.connect(); // 인증
System.out.println(client.system().ping().isPing()); // → true
for (SiteResponseV5 s : client.site().list()) // 사이트 목록
System.out.println(s.getSite_id() + " — " + s.getSite_name());
}

このブロックが true とサイト一覧を出力すれば準備完了です。以下1.1〜1.7で各ステップを詳しく説明します。

1.1 依存関係の追加​

JARファイルをクラスパスに追加してください。

# 빌드 (Gradle + Java 21)
cd plantpulse-api
./gradlew build

成果物は target/ に生成されます。

ファイル用途
target/plantpulse-api.jar既存プロジェクトに依存関係と共に統合する場合

1.2 クライアントの生成​

APIClient_V5 コンストラクタにオプションを直接渡します。

import plantpulse.api.v5.APIClient_V5;

APIClient_V5 client = new APIClient_V5(
"HTTPS", // 프로토콜: "HTTP" 또는 "HTTPS"
"100.68.69.41", // host
443, // port (REST API: 80=HTTP, 443=HTTPS)
"api", // user_id
"19ba7a54-1132-49f2-967e-3c6f5cd989a0", // token (api_key 발급용)
false); // debug

client.connect(); // 인증 + HTTP 클라이언트 초기화

// ... API 호출 ...

client.close(); // 종료

コンストラクタパラメータ​

パラメータタイプ説明
protocolString"HTTP" または "HTTPS"
hostStringサーバーホストまたはIP
portintサーバーポート
user_idString認証アカウントID
tokenString発行済みトークン (UUID形式)
debugbooleanHTTPリクエスト・レスポンス デバッグログ

認証フロー: connect() 呼び出し時に内部で user_id + token によりapi_keyを発行し、以降のすべてのコールでそのキーを自動的にヘッダーに含めます。ユーザーが直接扱う必要はありません。

1.3 最初のAPIコール — ping & サイト一覧​

import java.util.List;
import plantpulse.api.v5.APIClient_V5;
import plantpulse.api.v5.dto.response.SiteResponseV5;
import plantpulse.api.v5.dto.response.SystemPingResponseV5;

public class FirstCall {
public static void main(String[] args) throws Exception {

try (APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api",
"19ba7a54-1132-49f2-967e-3c6f5cd989a0", false)) {

client.connect();

// 1) 서버 헬스체크
SystemPingResponseV5 ping = client.system().ping();
System.out.println("Server alive: " + ping.isPing()
+ " (v" + ping.getVersion() + ")");

// 2) 사이트 목록 (typed DTO 리스트)
List<SiteResponseV5> sites = client.site().list();
for (SiteResponseV5 s : sites) {
System.out.println(s.getSite_id() + " — " + s.getSite_name());
}
}
}
}

実行結果:

Server alive: true (v5.0)
SITE_000001 — 대전 1공장
SITE_000002 — 천안 2공장

1.4 try-with-resources パターン​

APIClient_V5は AutoCloseableを実装しています。try-with-resources の使用を推奨します。

try (APIClient_V5 client = new APIClient_V5(proto, host, port, user, token, false)) {
client.connect();
// ... API 호출 ...
}
// close() 자동 호출 — HTTP 커넥션 정리

1.5 13種類のサービス一覧​

connect() 直後に以下のサービスメソッドですべてのドメインにアクセスできます (lazy初期化)。

client.system() // 헬스체크
client.site() // 사이트(공장)
client.customer() // 고객
client.employee() // 직원
client.product() // 제품
client.asset() // 자산 계층 (Area → Line → Equipment)
client.opc() // OPC 데이터 채널
client.tag() // 태그(데이터 포인트)
client.alarm() // 알람
client.order() // 작업지시
client.calendar() // 일정
client.path() // 자산 경로
client.flow() // Flow / Flow Node

1.6 V5 メソッドシグネチャ標準パターン​

すべてのドメインサービスは一貫したメソッドパターンに従います。ドメイン名が異なるだけで、使い方は同一です。

パターン戻り値タイプ失敗時の戻り値説明
create(req)*ResponseV5null登録
update(id, req)*ResponseV5null全体修正
delete(id)booleanfalse削除
get(id)*ResponseV5null単件照会
list()List<*ResponseV5>空リスト全体一覧
exists(id)booleanfalse存在確認
count()long0カウント

⚠️ 例外はスローされません。 通信エラーやサーバーのERRORレスポンスは、上表の安全なデフォルト値として返されます。エラー原因はログまたは BaseServiceV5.getErrorCode(env) で確認してください。詳細は レスポンス形式およびエラー処理 を参照。

1.7 デバッグモード​

コンストラクタの最後の引数を true にすると、HTTPリクエスト・レスポンスがコンソールに出力されます。

APIClient_V5 client = new APIClient_V5(
"HTTP", "100.68.69.41", 80, "api", TOKEN, true); // debug=true

出力例:

[V5] GET https://server/api/v5/site headers={api_key=ab****cd}
[V5] response: 200 {"_status":"OK","data":[{"site_id":"SITE_000001",...}]}

1.8 認証失敗時 — 503は「キーの間違い」ではない​

connect() は POST /api/v5/auth でトークンを api_key と交換します。成功判定はHTTP 200ではありません — meta.status が "OK" であり、かつ data.api_key が空ではないことが成功条件です。 第二条件があるのは、トークン検証は通過したがキー発行に失敗する経路が実際に存在するためです(その際、サーバーは500を返します)。

curl -s -X POST "http://<server>/api/v5/auth" \
-H "Content-Type: application/json; charset=UTF-8" \
-d '{"token":"<issued-token>"}'
# 200: {"data":{"api_key":"..."},"meta":{"status":"OK"},"errors":null}
レスポンスコード意味修正箇所
400E1001token がないか空ですリクエストボディ
422E1002ボディがJSONではありませんリクエストボディ
401E1100トークンが正しくありません資格情報
401E1102トークン有効期限切れ再発行で復旧します
401E1103トークン回収済み同じトークンは復旧しません — 新しく取得してください
429E1101同じIPでの失敗が蓄積しましたRetry-After 分待機後、値を修正して再試行
500E5000トークンは正しいが api_key 発行に失敗サーバー側 — 資格情報ではありません
503E5500トークンストレージに到達できず«判定自体がありません»サーバー側 — 資格情報ではありません
503を「認証失敗」として処理すると、誤った箇所を数日間調査することになります

サーバーはトークンストレージ(PostgreSQL)に到達できなかったとき、401を出しません。 401は「あなたの資格情報が間違っている」という主張であり、そのときサーバーはトークンが正しいかどうか分かっていないためです。 呼び出し側がこの二つを区別できなくなることが問題となります。

実際にそのような事例がありました — 2026-09-07、夜間e2eが8日間にわたり「22/22 失敗, E1100 Token authentication failed」を報告しましたが、プラットフォームログの真の原因は Connection to plantpulse-datalake:5432 refused でした。PostgreSQLの障害が8日間、資格情報エラーの顔をしていました。 現在はストレージ例外(SQLException · ソケット系)を原因チェーンまで辿って確認し、503 E5500 で回答します。

同様の理由で、503は失敗回数としてカウントしません。 カウントしていた場合、DB障害が正常な呼び出し側を429でロックしてしまい、障害の上にロックが重なることになります。

Javaクライアントはこの区別を例外メッセージとしてそのまま返します。メッセージを見てどこを修正するか決定してください。

メッセージ意味
V5 connect: /api/v5/auth call failed — …リクエストがサーバーに到達していません (アドレス・ポート・ファイアウォール)
V5 connect: auth endpoint unavailable (http=503) — server reached no verdict about the tokenサーバーが判定を出せませんでした — トークンを疑わないでください
V5 connect: authentication failed — …401/400系 — 資格情報またはリクエストを修正してください
V5 connect: api_key issuance failed — response=…meta.status はOKだがキーが空です — サーバー側
認証試行ロックは設定で変更可能です

同じIPでの認証失敗が engine.api.v5.auth.bruteforce.ip_limit (デフォルト 30) 回蓄積されると、engine.api.v5.auth.bruteforce.window.minutes (デフォルト 15) 分間429でロックされます。 engine.api.v5.auth.bruteforce.enabled=false でオフにできますが、オフにするとトークン代入攻撃に対して無防備になります。ボディがJSONでないリクエストは資格情報試行ではないためカウントしません。

次のステップ​