first
This commit is contained in:
+84
-15
@@ -1,25 +1,94 @@
|
||||
"""Vstupní bod aplikace pplcplapi.
|
||||
|
||||
Stateless FastAPI služba běžící v AppFactory za reverse proxy `/apps/<app-id>`.
|
||||
Multi-tenant proxy nad PPL CPL API (Create Package Label): tvorba zásilek
|
||||
a tisk etiket, tracking, objednávky svozu, číselníky, výdejní místa.
|
||||
|
||||
Přihlašovací údaje PPL se předávají per-request v X- hlavičkách, nikdy se
|
||||
neukládají ani nelogují. Jedinou výjimkou je in-memory cache OAuth tokenů
|
||||
(PPL limituje vydávání tokenů na 12/min), klíčovaná hashem údajů.
|
||||
"""
|
||||
import os
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
APP_NAME = os.getenv("APP_NAME", "PPL CPL API")
|
||||
APP_VERSION = os.getenv("APP_VERSION", "1.0.0")
|
||||
ROOT_PATH = os.getenv("ROOT_PATH", "")
|
||||
from .config import APP_NAME, APP_VERSION, ROOT_PATH
|
||||
from .cpl_client import close_client
|
||||
from .errors import register_exception_handlers
|
||||
from .logging_config import configure_logging
|
||||
from .routers import codelists, customer, lookups, meta, orders, proxy, shipments
|
||||
|
||||
configure_logging()
|
||||
|
||||
DESCRIPTION = """
|
||||
Proxy nad **PPL CPL API** (Create Package Label) — tvorba zásilek a etiket,
|
||||
tracking, objednávky svozu, číselníky, výdejní místa a našeptávač adres.
|
||||
|
||||
### Přihlašovací údaje (hlavičky)
|
||||
Secrets se předávají v hlavičkách u každého requestu — nikdy v těle ani v URL:
|
||||
|
||||
- `X-Client-Id` — PPL CPL ClientId
|
||||
- `X-Client-Secret` — PPL CPL ClientSecret
|
||||
- `X-Environment` — volitelně `production` (default) nebo `test`
|
||||
|
||||
Služba si sama vyžádá a cachuje OAuth Bearer token (platnost 30 min,
|
||||
PPL limit 12 tokenů/min) a dodržuje minimální rozestup requestů 40 ms.
|
||||
|
||||
### Asynchronní tok zásilek
|
||||
CPL API zpracovává zásilky i objednávky dávkově:
|
||||
`POST /shipments/batch` vrátí `batchId` → stav se sleduje přes
|
||||
`GET /shipments/batch/{batchId}` → etikety přes `GET /shipments/batch/{batchId}/labels`.
|
||||
Pro jednoduché použití slouží `POST /shipments/create-and-wait`
|
||||
(a `POST /orders/create-and-wait`), které celý tok provedou v jednom requestu.
|
||||
|
||||
### Diakritika
|
||||
CPL API přijímá pouze Latin znaky bez diakritiky. Texty v tělech create
|
||||
requestů se defaultně transliterují (`Jiří` → `Jiri`); vypnout lze query
|
||||
parametrem `transliterate=false`.
|
||||
|
||||
### Generická proxy
|
||||
Cokoliv, co nemá vlastní endpoint: `/proxy/{cesta}` předá request 1:1 na CPL
|
||||
API s doplněnou autentizací (např. `GET /proxy/codelist/product?Limit=10&Offset=0`).
|
||||
|
||||
### Chyby
|
||||
JSON `{error, message, detail}` — `detail` obsahuje problem+json z PPL.
|
||||
400 = validační chyba, 401 = chybějící/odmítnuté přihlašovací údaje,
|
||||
403 = chybí oprávnění, 404 = záznam neexistuje, 429 = rate limit,
|
||||
502 = výpadek PPL.
|
||||
"""
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
yield
|
||||
await close_client()
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
title=APP_NAME,
|
||||
version=APP_VERSION,
|
||||
root_path=ROOT_PATH
|
||||
description=DESCRIPTION,
|
||||
root_path=ROOT_PATH,
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
@app.get("/health")
|
||||
def health():
|
||||
return {"status": "ok"}
|
||||
register_exception_handlers(app)
|
||||
|
||||
@app.get("/version")
|
||||
def version():
|
||||
return {
|
||||
"app": APP_NAME,
|
||||
"version": APP_VERSION,
|
||||
"language": "python",
|
||||
"root_path": ROOT_PATH
|
||||
}
|
||||
app.include_router(meta.router)
|
||||
app.include_router(shipments.router)
|
||||
app.include_router(orders.router)
|
||||
app.include_router(codelists.router)
|
||||
app.include_router(lookups.router)
|
||||
app.include_router(customer.router)
|
||||
app.include_router(proxy.router)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(
|
||||
"app.main:app",
|
||||
host="0.0.0.0",
|
||||
port=int(os.getenv("PORT", "8000")),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user