Upsert pattern
API-ul folosește pattern-ul upsert: o singură cerere PUT creează un obiect nou sau actualizează unul existent. Nu trebuie să verifici dacă obiectul există în sistem — API-ul face asta automat.
De ce este necesar
Într-un API REST clasic, pentru sincronizarea datelor ai nevoie de:
1. GET /listings/external/APT-001 # Verifică existența
2. Dacă 404 → POST /listings # Creează
Dacă 200 → PUT /listings/42 # Actualizează
Cu pattern-ul upsert totul e mai simplu:
1. PUT /listings { externalId: "APT-001", ... }
# API-ul creează sau actualizează singur
Cum funcționează
| Situație | Ce se întâmplă |
|---|---|
| Obiectul nu este găsit | Se creează unul nou |
| Obiectul este găsit | Se actualizează cel existent |
Căutarea se face după id sau externalId — ceea ce ai transmis în cerere.
Exemplu: creare
Prima cerere cu externalId: "APT-001" creează anunțul:
curl -X PUT https://crm.rentix.md/api/v1/listings \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalId": "APT-001",
"announcementType": "rent",
"propertyType": "residential",
"propertySecondaryType": "apartment",
"announcementValue": 500,
"announcementCurrency": "EUR"
}'
{
"id": 42,
"externalId": "APT-001",
"status": "draft",
"created": true,
"updated": false
}
Observă: created: true — obiectul a fost creat.
Exemplu: actualizare
O cerere repetată cu același externalId actualizează anunțul:
curl -X PUT https://crm.rentix.md/api/v1/listings \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"externalId": "APT-001",
"announcementValue": 600
}'
{
"id": 42,
"externalId": "APT-001",
"status": "draft",
"created": false,
"updated": true
}
Acum updated: true — obiectul a fost actualizat.
Actualizare parțială
La actualizare transmite doar câmpurile modificate. Celelalte își păstrează valorile:
// Prima cerere — creare completă
{
"externalId": "APT-001",
"announcementType": "rent",
"announcementValue": 500,
"propertyArea": 65,
"propertyFloorNumber": 3
}
// A doua cerere — schimbăm doar prețul
{
"externalId": "APT-001",
"announcementValue": 600
}
// propertyArea și propertyFloorNumber rămân neschimbate
Golirea câmpurilor
Pentru a goli un câmp (șterge valoarea), trimite null:
{
"externalId": "APT-001",
"propertyFloorNumber": null
}
După această cerere propertyFloorNumber va fi gol.
Avantaje
Simplitatea integrării
Un singur endpoint pentru toate cazurile. Nu trebuie să scrii logică de verificare a existenței.
Idempotență
O cerere repetată cu aceleași date nu va crea un duplicat — doar va actualiza obiectul existent. Acest lucru e important la eșecuri de rețea: poți repeta cererea în siguranță.
Atomicitate
Crearea sau actualizarea are loc într-o singură tranzacție. Nu există situația „am verificat — nu era, am creat — duplicat".
Bulk upsert
Același principiu funcționează pentru operații în masă. Până la 100 obiecte per cerere. Fiecare operație trebuie să conțină câmpul op:
curl -X POST https://crm.rentix.md/api/v1/listings/bulk \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{ "op": "upsert", "externalId": "APT-001", "announcementValue": 500 },
{ "op": "upsert", "externalId": "APT-002", "announcementValue": 700 },
{ "op": "upsert", "externalId": "APT-003", "announcementValue": 450 }
]
}'
{
"results": [
{ "op": "upsert", "externalId": "APT-001", "id": 42, "success": true, "created": false, "updated": true },
{ "op": "upsert", "externalId": "APT-002", "id": 43, "success": true, "created": true, "updated": false },
{ "op": "upsert", "externalId": "APT-003", "id": 44, "success": true, "created": true, "updated": false }
],
"summary": { "total": 3, "succeeded": 3, "failed": 0 }
}
Limitări
id cât și externalId — va fi eroare. Alege o singură metodă de identificare.| Resursă | Endpoint |
|---|---|
| Anunțuri | PUT /listings |
| Utilizatori | PUT /users |