3. Antwortformate und Fehlerbehandlung
Alle Aufrufe der V5 API liefern ein typisiertes DTO oder boolean/long zurück. Im Fehlerfall werden die folgenden sicheren Standardwerte zurückgegeben.
3.1 V5-Antwortmuster
| Methodenmuster | Rückgabe bei Erfolg | Rückgabe bei Fehler |
|---|---|---|
create(req) / update(id, req) / get(id) | *ResponseV5-Instanz | null |
list()-Familie | List<*ResponseV5> | leere Liste (niemals null) |
delete(id) | true | false |
exists(id) | true (vorhanden) | false (nicht vorhanden oder Fehler) |
count()-Familie | long (≥0) | 0 |
Order-Lebenszyklus (start/end/pause/resume/abort) | true (Erfolg) | false (z. B. Übergang nicht möglich) |
Es werden keine Exceptions geworfen. HTTP-Fehler, Server-ERROR und fehlgeschlagenes JSON-Parsing werden allesamt durch die sicheren Standardwerte aus der obigen Tabelle abgefangen. Die Fehlerursache lässt sich im Debug-Log oder in
_code/_messagedes Envelope nachvollziehen.
3.2 Internes Wire-Format (zur Information)
Der V5-Server antwortet mit einem Envelope der folgenden Form. Die Client-Bibliothek parst diesen automatisch, im normalen Betrieb müssen Sie sich also nicht darum kümmern.
// 단건 성공
{ "_status": "OK", "data": { ... } }
// 목록 성공
{ "_status": "OK", "data": [ { ... }, { ... } ] }
// 목록 — items 키 안에 배열
{ "_status": "OK", "data": { "items": [ ... ] } }
// 에러
{
"_status": "ERROR",
"_code": "E1002",
"_message": "validation failed: ...",
"_http_status": 400
}
3.3 Zuordnung der V5-ErrorCodes
Wenn der Server eine ERROR-Antwort sendet, enthält das Feld _code einen der folgenden Codes.
| Code | Bedeutung | Typische Ursache |
|---|---|---|
E1001 | INVALID_INPUT | Pflichtfeld fehlt, Typkonflikt |
E1002 | VALIDATION_FAILED | Verstoß gegen ID-Präfix (SITE_ usw.) |
E1100 | UNAUTHORIZED | api_key fehlt oder ist ungültig |
E1101 | FORBIDDEN | Unzureichende Berechtigung |
E1200 | CONFLICT | Doppelte ID, FK-Konflikt |
E1300 | NOT_FOUND | Keine Entsprechung zur ID |
E1400 | DOMAIN_RULE_VIOLATION | z. B. Order-Statusübergang nicht möglich |
E1500 | DEPENDENCY_FAILED | Fehlende Antwort eines externen Systems |
E1900 | INTERNAL_ERROR | Interner Serverfehler |
3.4 Fehlerinformationen auslesen
Da die V5-Servicemethoden den Envelope nicht direkt offenlegen, lassen sich Fehlerdetails auf zwei Wegen ermitteln.
Weg 1 — Debug-Modus
APIClient_V5 client = new APIClient_V5(proto, host, port, user, token, true);
client.connect();
SiteResponseV5 result = client.site().create(req);
if (result == null) {
// 콘솔 로그에서 envelope 확인 가능
System.err.println("등록 실패 — 디버그 로그 확인");
}
Konsolenausgabe:
[V5] POST /api/v5/site body={...}
[V5] response: 400 {"_status":"ERROR","_code":"E1002","_message":"site_id must start with SITE_"}
Weg 2 — Statische Methoden von BaseServiceV5 verwenden (eigene Erweiterung)
Die Helper von BaseServiceV5 extrahieren Fehlerinformationen aus einer JSONObject-Antwort. Das ist nützlich, wenn Sie die Bibliothek erweitern und einen eigenen Service bauen, der den Envelope erfasst.
import plantpulse.api.v5.service.BaseServiceV5;
import plantpulse.json.JSONObject;
// 환경 (envelope) JSONObject 가 있다면
String code = BaseServiceV5.getErrorCode(env); // 예: "E1002"
String message = BaseServiceV5.getErrorMessage(env); // 예: "validation failed: ..."
int httpStatus = BaseServiceV5.getHttpStatus(env); // 예: 400
3.5 Sichere Aufrufmuster
CRUD-Aufruf
import plantpulse.api.v5.dto.request.SiteRequestV5;
import plantpulse.api.v5.dto.response.SiteResponseV5;
SiteRequestV5 req = new SiteRequestV5();
req.setSite_id("SITE_DJ");
req.setSite_name("대전공장");
SiteResponseV5 created = client.site().create(req);
if (created == null) {
// 실패 처리 — 예: 알람, 재시도, 다른 경로 시도
log.warn("사이트 생성 실패");
return;
}
System.out.println("등록 완료: " + created.getSite_id());
Listenaufruf
List<SiteResponseV5> sites = client.site().list();
// 실패해도 null 이 아님 — 그대로 순회 가능
for (SiteResponseV5 s : sites) {
System.out.println(s.getSite_id());
}
if (sites.isEmpty()) {
log.info("등록된 사이트 없음");
}
Existenzprüfung → Abfrage
if (client.site().exists("SITE_DJ")) {
SiteResponseV5 site = client.site().get("SITE_DJ");
// ...
}
Order-Lebenszyklus (Rückgabe boolean)
String orderId = "ORD_20260514_001";
if (!client.order().start(orderId)) {
// 전이 불가 (예: 이미 START 상태)
log.warn("작업 시작 실패 — 현재 상태 확인");
return;
}
// 작업 진행 ...
if (!client.order().end(orderId)) {
log.warn("작업 종료 실패");
}
3.6 Wiederholungsmuster
V5 führt keine automatischen Wiederholungen durch. Wenn Sie Retries für vorübergehende Netzwerkfehler benötigen, implementieren Sie diese selbst.
import java.util.function.Supplier;
public static <T> T callWithRetry(Supplier<T> apiCall, int maxRetries, long baseDelayMs) {
int attempt = 0;
while (true) {
T result = apiCall.get();
if (result != null) return result; // 성공
if (++attempt >= maxRetries) return null; // 포기
try {
Thread.sleep(baseDelayMs * attempt); // 지수 백오프
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
return null;
}
}
}
// 사용
SiteResponseV5 site = callWithRetry(
() -> client.site().get("SITE_DJ"),
3,
1_000L);
3.7 Leere Antwort und null-Antwort unterscheiden
In V5 umfassen null bzw. false beide der folgenden Bedeutungen:
- Auf dem Server sind keine Daten vorhanden (
NOT_FOUND,E1300) - Der Aufruf ist fehlgeschlagen (Netzwerkfehler, fehlgeschlagene Validierung usw.)
Zur Unterscheidung können Sie zusätzlich exists() verwenden.
if (!client.site().exists("SITE_DJ")) {
log.info("사이트가 등록되어 있지 않습니다");
// 신규 등록 로직
} else {
SiteResponseV5 site = client.site().get("SITE_DJ");
if (site == null) {
log.error("사이트는 존재하지만 조회 실패 — 일시적 오류 가능");
}
}
Nächste Schritte
- System-Service — Health-Check
- Site-Service — Einstiegspunkt für Stammdaten