first
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
# PPL CPL API — přehled služby
|
||||
|
||||
Stateless multi-tenant proxy nad PPL CPL API (Create Package Label).
|
||||
Upstream: `https://api.dhl.com/ecs/ppl/myapi2` (production),
|
||||
`https://api-dev.dhl.com/ecs/ppl/myapi2` (test).
|
||||
Dokumentace PPL: https://ppl-cpl-api.apidog.io/
|
||||
|
||||
## Autentizace
|
||||
|
||||
Každý request nese hlavičky:
|
||||
|
||||
- `X-Client-Id` — PPL ClientId (secret)
|
||||
- `X-Client-Secret` — PPL ClientSecret (secret)
|
||||
- `X-Environment` — `production` (default) nebo `test`
|
||||
- `Accept-Language` — volitelně, předává se do PPL (např. `cs-CZ`)
|
||||
|
||||
Služba z údajů získá OAuth Bearer token (`POST {base}/login/getAccessToken`,
|
||||
grant `client_credentials`, scope `myapi2`) a **cachuje ho in-memory** pod
|
||||
SHA-256 hashem údajů. Důvod: PPL vydá max. 12 tokenů/min a token platí 30 minut.
|
||||
Token se obnovuje 60 s před expirací; na HTTP 401 z PPL se jednou obnoví
|
||||
a request se zopakuje.
|
||||
|
||||
## Limity PPL, které služba respektuje
|
||||
|
||||
- min. 40 ms rozestup mezi requesty (globální throttle v procesu),
|
||||
- max. 1000 zásilek / 100 objednávek v jednom batchi,
|
||||
- batchId platí 30 dní,
|
||||
- pouze Latin znaky bez diakritiky — viz transliterace níže.
|
||||
|
||||
## Transliterace diakritiky
|
||||
|
||||
CPL API odmítá texty s diakritikou. Těla `POST /shipments/batch`,
|
||||
`/shipments/create-and-wait`, `/orders/batch` a `/orders/create-and-wait`
|
||||
se defaultně rekurzivně transliterují přes unidecode (`Jiří Dvořák` →
|
||||
`Jiri Dvorak`). Chování:
|
||||
|
||||
- query parametr `transliterate=true|false` na requestu má přednost,
|
||||
- jinak platí env `CPL_TRANSLITERATE` (default `true`),
|
||||
- generická `/proxy/...` NEtransliteruje nikdy (předává 1:1).
|
||||
|
||||
## Chybové odpovědi
|
||||
|
||||
Jednotný JSON `{error, message, detail}`; `detail` obsahuje původní
|
||||
problem+json z PPL (typ, title, errors...).
|
||||
|
||||
| Status | Význam |
|
||||
|---|---|
|
||||
| 400 | validační chyba (vstup zde nebo v PPL) |
|
||||
| 401 | chybějící X- hlavičky nebo PPL odmítlo údaje/token |
|
||||
| 403 | chybí oprávnění (role) k metodě v PPL |
|
||||
| 404 | batch/zásilka/objednávka neexistuje |
|
||||
| 429 | rate limit PPL |
|
||||
| 502 | výpadek / neočekávaná chyba PPL |
|
||||
|
||||
Všechny chyby se logují (bez secrets) — žádná tichá selhání.
|
||||
|
||||
## Konfigurace (environment variables)
|
||||
|
||||
| Proměnná | Default | Význam |
|
||||
|---|---|---|
|
||||
| `ROOT_PATH` | `""` | prefix za reverse proxy (`/apps/pplcplapi`) |
|
||||
| `CPL_DEFAULT_ENVIRONMENT` | `production` | prostředí bez hlavičky X-Environment |
|
||||
| `CPL_PRODUCTION_BASE_URL` / `CPL_TEST_BASE_URL` | viz výše | base URL upstreamu |
|
||||
| `CPL_OAUTH_SCOPE` | `myapi2` | OAuth scope |
|
||||
| `CPL_TRANSLITERATE` | `true` | default transliterace diakritiky |
|
||||
| `UPSTREAM_TIMEOUT_SECONDS` | `60` | timeout volání PPL |
|
||||
| `TOKEN_REFRESH_MARGIN_SECONDS` | `60` | předstih obnovy tokenu |
|
||||
| `MIN_REQUEST_INTERVAL_SECONDS` | `0.04` | rozestup requestů na PPL |
|
||||
| `BATCH_POLL_INTERVAL_SECONDS` | `1.0` | interval pollingu create-and-wait |
|
||||
| `BATCH_WAIT_TIMEOUT_SECONDS` | `30` | default timeout create-and-wait |
|
||||
| `LOG_LEVEL` | `INFO` | úroveň logování |
|
||||
|
||||
Žádné secrets se nekonfigurují přes env — vše chodí per-request v hlavičkách.
|
||||
|
||||
## Struktura kódu
|
||||
|
||||
```
|
||||
app/
|
||||
main.py — FastAPI aplikace, root_path, popis pro Swagger
|
||||
config.py — env konfigurace
|
||||
credentials.py — X- hlavičky -> Credentials (dependency)
|
||||
token_cache.py — in-memory cache OAuth tokenů
|
||||
cpl_client.py — autentizovaný httpx klient, throttle, relay helpery
|
||||
transliterate.py — rekurzivní unidecode JSON těl
|
||||
errors.py — typované chyby + handlery
|
||||
routers/
|
||||
meta.py — /health, /version
|
||||
shipments.py — zásilky, etikety, tracking, storno, celní dokumenty
|
||||
orders.py — objednávky svozu/přepravy
|
||||
codelists.py — číselníky, /version-information, /cpl-info
|
||||
lookups.py — /access-points, /address-whisper, /routing, /data/{guid}
|
||||
customer.py — /customer, /customer/addresses, /customer/number-range
|
||||
proxy.py — generická proxy /proxy/{cesta}
|
||||
```
|
||||
Reference in New Issue
Block a user