Endpoint-uri de stare, identitate și meta
Endpoint-uri de stare, identitate și meta
Sunt endpoint-urile mici, de suport, care însoțesc suprafața fiscală a API-ului. Există pentru nevoi operaționale, nu pentru logică de business: sonde de liveness și readiness pentru load balancere și orchestratoare, un apel de introspecție care permite unei integrări să confirme cu ce cheie (sau ca ce utilizator) este autentificată în acest moment, un fișier robots care ține motoarele de căutare departe de host-ul API-ului și suprafața OpenAPI propriu-zisă, ca Postman, generatoarele de SDK și cititorii umani să poată descoperi fără credențiale toate celelalte endpoint-uri.
Toate sunt rutate la rădăcina host-ului, nu sub /api/v1/, pentru că sunt parte de infrastructură, nu endpoint-uri de business versionate. Singurul care cere autentificare este GET /api/v1/me.
GET /health
Cea mai ieftină verificare de liveness posibilă. Nu face I/O — răspunde doar cu timestamp-ul curent și versiunea pachetului din build-ul care rulează. Folosește-l pentru verificările de stare de la load balancere, livenessProbe din Kubernetes, verificările de stare ale unui AWS Target Group și orice altă sondă de tip „procesul este sus?”.
- Autentificare: niciuna — public.
Răspuns (200 OK)
| Câmp | Tip | Note |
|---|---|---|
status | string | Mereu "ok". Dacă nu poți ajunge la endpoint, procesul este picat. |
timestamp | string (ISO 8601) | Ceasul serverului în momentul răspunsului. |
version | string | Versiunea pachetului API (process.env.npm_package_version), sau "0.0.0" dacă nu este setată. |
Exemplu
curl https://api.e-bon.ro/health
{
"status": "ok",
"timestamp": "2026-04-09T08:10:00.000Z",
"version": "0.0.0"
}
GET /health/firebase
Verificare cap-coadă a conectivității cu Firestore. Handler-ul scrie un document temporar în colecția _health, îl citește înapoi și îl șterge — astfel un 200 confirmă credențialele, accesibilitatea de rețea și calea de citire+scriere către baza de date reală. Round-trip-ul total este raportat în latencyMs.
- Autentificare: niciuna — public.
Răspunsuri
200 OK — Firestore este accesibil cap-coadă:
| Câmp | Tip | Note |
|---|---|---|
status | string | Mereu "ok". |
firestore | string | Mereu "connected". |
latencyMs | integer | Round-trip scriere + citire + ștergere, în milisecunde. |
timestamp | string (ISO 8601) | Ceasul serverului în momentul răspunsului. |
503 Service Unavailable — Firestore este inaccesibil. Corpul are una din două forme, în funcție de locul în care s-a produs eroarea:
Apelul către Firestore a aruncat o excepție (cazul tipic — credențiale, rețea, permisiune refuzată):
| Câmp | Tip | Note |
|---|---|---|
status | string | Mereu "error". |
firestore | string | Mereu "disconnected". |
message | string | Mesajul excepției aruncate (sau "Unknown error"). |
latencyMs | integer | Timpul scurs până la apariția erorii, în milisecunde. |
Citirea de control a returnat un snapshot gol (scrierea a reușit, dar documentul nu este vizibil — extrem de rar, în general indică o anomalie de consistență Firestore):
| Câmp | Tip | Note |
|---|---|---|
status | string | Mereu "error". |
message | string | Mereu "Firestore read-back failed". |
latencyMs | integer | Round-trip până la și inclusiv citirea de control eșuată. |
status — a doua formă de 503 nu include câmpul firestore. Nu te baza pe prezența lui.Exemplu
curl https://api.e-bon.ro/health/firebase
{
"status": "ok",
"firestore": "connected",
"latencyMs": 42,
"timestamp": "2026-04-09T08:10:00.000Z"
}
GET /health/ready
Verificare completă de readiness. Agregează starea per componentă într-un singur răspuns, ca un orchestrator să poată decide ruterea traficului în funcție de fiecare dependență externă de care API-ul are nevoie pentru a face muncă utilă. În prezent singura componentă verificată este firestore, folosind aceeași sondă scriere+citire+ștergere ca /health/firebase (pe documentul _health/ready); dependențele externe viitoare vor apărea ca chei suplimentare în components.
- Autentificare: niciuna — public.
Răspunsuri
200 OK — toate componentele sunt sănătoase.
503 Service Unavailable — cel puțin o componentă este nesănătoasă.
Forma corpului este identică pentru ambele coduri de stare:
| Câmp | Tip | Note |
|---|---|---|
status | string | "ok" când fiecare componentă este "ok", "error" în caz contrar. |
components.firestore.status | string | "ok", "error" sau "skipped". |
components.firestore.latencyMs | integer | Round-trip pentru sonda Firestore, în milisecunde. |
components.firestore.message | string (opțional) | Apare când status este "error". Fie mesajul excepției, fie "Firestore read-back failed". |
timestamp | string (ISO 8601) | Ceasul serverului în momentul răspunsului. |
Exemplu
curl https://api.e-bon.ro/health/ready
{
"status": "ok",
"components": {
"firestore": { "status": "ok", "latencyMs": 38 }
},
"timestamp": "2026-04-09T08:10:00.000Z"
}
GET /api/v1/me
Introspecția identității. Returnează orgId, scopes și keyLabel ale credențialului care a autentificat cererea. Util ca verificare unică pentru a confirma că o cheie API nou-emisă este conectată corect, sau pentru o interfață de admin care vrea să afișeze „ești autentificat ca X”.
- Autentificare: obligatorie — cheie API sau JWT din Portal (autentificare combinată).
Răspuns (200 OK)
| Câmp | Tip | Note |
|---|---|---|
orgId | string | Organizația căreia îi aparține credențialul. |
scopes | string | Permisiunile atașate cheii API. Vezi Autentificare › Permisiuni pentru lista canonică. |
keyLabel | string | Eticheta lizibilă atribuită cheii API la creare. |
Erori
UNAUTHORIZED(401) — fără credențial, credențial malformat, sau cheia este inactivă / revocată.
Exemple
Cu o cheie API (cazul cel mai frecvent):
curl https://api.e-bon.ro/api/v1/me \
-H "Authorization: Bearer ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Același apel cu forma alternativă a antetului x-api-key:
curl https://api.e-bon.ro/api/v1/me \
-H "x-api-key: ebon_live_acme_corp_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
Cu un JWT din Portal (Portalul și aplicația mobilă folosesc acest flux):
curl https://api.e-bon.ro/api/v1/me \
-H "Authorization: Bearer eyJhbGciOi..."
{
"orgId": "acme_corp",
"scopes": ["receipts", "commands", "devices:read"],
"keyLabel": "POS Integration"
}
GET /robots.txt
Fișier de excludere pentru crawlere. Returnează text/plain cu o interdicție totală, ca niciun crawler să nu indexeze host-ul API-ului — API-ul nu este un site web și nu are conținut care să merite indexat.
- Autentificare: niciuna — public.
Răspuns (200 OK)
Content-Type: text/plain cu corpul:
User-agent: *
Disallow: /
Exemplu
curl https://api.e-bon.ro/robots.txt
GET /docs și /docs/openapi.json
Suprafața OpenAPI completă, expusă în două variante, ca atât oamenii, cât și uneltele să poată descoperi orice endpoint fără autentificare.
- Autentificare: niciuna — ambele rute sunt publice intenționat, ca orice unealtă să poată descoperi contractul API-ului fără credențiale.
GET /docs
Swagger UI (HTML randat). Deschide-l în browser ca să răsfoiești catalogul de endpoint-uri interactiv, să extinzi schemele de cerere/răspuns și să rulezi cereri către API-ul real.
https://api.e-bon.ro/docs
GET /docs/openapi.json
Specificația OpenAPI 3 brută, ca un singur document JSON. Trimite-o către Postman („Import → Link” pe acest URL), către generatoare de SDK-uri compatibile OpenAPI, sau către orice altceva care poate consuma o specificație OpenAPI 3.
curl https://api.e-bon.ro/docs/openapi.json
/docs și /docs/openapi.json sunt publice intenționat — livrează contractul public al API-ului, nu datele lui. Le poți pune ca link din unelte interne, pagini de onboarding pentru parteneri sau ghiduri de integrare orientate către clienți, fără să te îngrijorezi pentru autentificare.Folosește aceste endpoint-uri dintr-un load balancer sau monitor de uptime
Cele două sonde sunt gândite pentru straturi diferite ale orchestrației:
- Sondă de liveness →
GET /health. Ieftină, fără I/O extern, fără round-trip Firestore. Folosește-o pentrulivenessProbedin Kubernetes, verificările de stare ale unui AWS Target Group,HEALTHCHECKdin Docker și pentru monitoarele de uptime care ar trebui să se declanșeze numai când procesul în sine este blocat. - Sondă de readiness →
GET /health/ready. Execută o operațiune reală de scriere+citire+ștergere în Firestore la fiecare apel. Folosește-o pentrureadinessProbedin Kubernetes și pentru orice altă barieră care trebuie să țină traficul departe de un pod care este sus, dar nu poate servi cereri reale pentru că o dependență externă este picată.
Un exemplu minim Kubernetes:
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /health/ready
port: 3000
initialDelaySeconds: 15
periodSeconds: 30
/health/firebase și /health/ready execută o scriere, o citire și o ștergere reală în Firestore la fiecare cerere. Nu le scrapa în fiecare secundă dintr-un monitor de uptime — păstrează intervalul la 30 de secunde sau mai mult. Pentru verificări de liveness sub-secundă folosește întotdeauna /health, care nu face I/O.Descoperă suprafața API-ului
Pentru explorare interactivă în browser, trimite un coleg la https://api.e-bon.ro/docs (Swagger UI). Pentru unelte care vor să consume direct specificația — import în Postman pe bază de URL, generatoare de SDK-uri, lintere OpenAPI — trimite-le la https://api.e-bon.ro/docs/openapi.json. Colecția Postman organizată manual (cu corpuri exemplificative și dosare grupate pe suprafață) are o pagină proprie; vezi Colecție Postman.
Pași următori
- Prezentare generală API — URL de bază, format de eroare, limite de rată, idempotență și restricții pe planuri.
- Autentificare — formatul cheii API, lista canonică de permisiuni și cum trimiți credențialele.
- Colecție Postman — importă colecția organizată sau dă-i Postman-ului URL-ul brut
/docs/openapi.json.
Endpoint-uri de autentificare
Endpoint-uri REST sub /api/v1/auth — înregistrare, autentificare, parolă uitată, reîmprospătare și deconectare — care emit și revocă perechea de jetoane JWT de acces + reîmprospătare folosită de Portalul e-bon și de aplicația mobilă E-BON.
Idempotență
Folosește antetul Idempotency-Key pentru a face reluările sigure în POS — răspunsul memorat este returnat 24 de ore și eviți bonurile tipărite de două ori.