REST vs GraphQL: când alegi pe care și cum NU le combini
REST și GraphQL nu sunt concurenți direcți: REST este un stil arhitectural, GraphQL un query language. Cum alegi și ce capcane evites.
Cuprins
REST și GraphQL nu sunt concurenți direcți, ci instrumente cu filozofii diferite: REST este un stil arhitectural bazat pe resurse identificate prin URL-uri, iar GraphQL este un query language prin care clientul cere exact câmpurile de care are nevoie. Diferența practică este că în REST serverul decide forma răspunsului, iar în GraphQL clientul o decide.
Confuzia frecventă este că ar trebui să alegi unul sau celălalt ca pe o religie. Nu trebuie. Alegerea depinde de cine consumă API-ul, cât de variate sunt cererile de date, ce tooling există în echipă și cât de mult contează caching-ul HTTP. Există scenarii în care fiecare câștigă clar și scenarii în care le combini, dar numai dacă ai un motiv explicit pentru fiecare strat.
Ce este fiecare: REST ca stil arhitectural, GraphQL ca query language?
REST (Representational State Transfer) a fost definit de Roy Fielding în teza sa din 2000 ca un set de constrângeri arhitecturale pentru sisteme distribuite pe web. Constrângerile centrale: resurse identificate prin URL-uri (/users/42, /orders/88), operații prin verbe HTTP (GET, POST, PUT, DELETE), natura stateless a cererilor (fiecare cerere conține tot ce trebuie, inclusiv tokenul de autentificare) și răspunsuri marcabile ca cacheable la nivel HTTP.
GraphQL a fost creat de Facebook în 2012 și publicat ca open source în 2015. Toate cererile merg la un singur endpoint (de obicei /graphql), prin POST, indiferent de operație. Clientul trimite o interogare structurată care specifică exact câmpurile vrute, iar serverul răspunde cu exact acel șablon.
Care sunt punctele forte ale REST-ului?
- Caching HTTP nativ. Răspunsul unui
GET /products/123poate fi cached de browser, CDN sau reverse proxy pe baza header-elorCache-ControlșiETag. În GraphQL, toate cererile suntPOST, iar caching-ul standard HTTP nu se aplică fără soluții intermediare. - Tooling matur. OpenAPI permite generarea automată de documentație, SDK-uri și mock-uri dintr-o singură schemă.
curlși Postman funcționează direct, fără client special. - Debugging simplu. Fiecare cerere are un URL distinct, un verb explicit și un cod de status HTTP. Poți reproduce orice cerere cu un simplu
curl. În GraphQL, tot traficul arată la fel la nivel de rețea și ai nevoie de tooling specific. - Semantică HTTP standardizată.
404,401,403sunt un contract public. GraphQL returnează aproape întotdeauna200chiar și pentru erori, cu detaliile în câmpulerrorsdin răspuns.
Care sunt punctele forte ale GraphQL-ului?
- Clientul controlează forma răspunsului. Aplicația mobilă cere trei câmpuri; aplicația desktop cere cincisprezece. Cu REST, ori faci endpoint-uri separate, ori clientul primește mai mult decât are nevoie. Cu GraphQL, ambele cazuri sunt servite de aceeași schemă.
- O singură cerere pentru date din surse multiple. Un ecran de profil afișează date din trei resurse. Cu REST, faci trei cereri. Cu GraphQL, faci una.
- Schemă strict tipizată ca documentație live. Schema GraphQL este un contract explicit între server și client, cu tipuri, câmpuri și descrieri. Clientul poate inspecta schema (introspection) și știe exact ce poate cere.
- Evoluție fără versionare explicită. Adaugi câmpuri noi la schemă fără să strici clienții existenți. Marchezi câmpurile vechi ca
@deprecated. Clienții migrează în ritmul lor.
Cum am ales REST pentru produsele crawlerra?
Pentru produsele proprii și pentru cele B2B pe care le livrăm clienților, REST este alegerea noastră consistentă. Motivele sunt operaționale: ecosystem mai matur de tooling (OpenAPI, generare de SDK-uri, caching pe HTTP), depanare ușoară prin curl sau Postman, și faptul că Spring Boot @RestController este standardul natural în stiva Java pe care o folosim în crawlerra-backend. Caching-ul la nivelul HTTP, util atât la gateway cât și la CDN, funcționează fără configurație suplimentară.
GraphQL ar fi relevant dacă am livra o platformă cu UI extrem de flexibil, unde mai mulți consumatori diferiți cer combinații variate de câmpuri din același set de date. La profilul nostru actual de produse B2B cu UI dedicat per produs, complexitatea adăugată de un strat GraphQL nu ar aduce beneficii clare față de endpoint-urile REST bine definite și documentate. Alegerea se schimbă dacă cerințele se schimbă; nu există un câștigător universal între cele două abordări.
Care sunt capcanele tipice?
- N+1 în GraphQL. Un resolver naiv face un
SELECTseparat în Postgres pentru fiecare obiect dintr-o listă. La 50 de înregistrări, ajungi la 51 de query-uri în loc de 2. Soluția standard este DataLoader: grupează cererile identice din același ciclu de execuție și le rezolvă printr-o singură interogare cuIN. Fără DataLoader, GraphQL devine mai lent decât REST echivalent pe date relaționale, nu mai rapid. - Over-fetching în REST. Endpoint-ul
/users/{id}returnează toate câmpurile, inclusiv cele pe care aplicația mobilă nu le folosește niciodată. La scară, transferi date inutile și supraîncărci rețeaua. Soluția pragmatică: parametri de selecție a câmpurilor sau endpoint-uri separate pentru consumatori cu nevoi foarte diferite. - Under-fetching în REST. Clientul face N cereri pentru a aduna date legate. Cu 20 de produse și câte un apel pentru categorie, ajungi la 21 de cereri. Idempotența cererilor
GETsimplifică caching-ul unui endpoint de batch dedicat care aduce datele legate dintr-o singură cerere. - Endpoint-uri nedocumentate în REST. Fără o schemă OpenAPI actualizată, endpoint-urile descoperite doar prin grep în cod devin o sursă de risc la integrări noi sau la rotirea de personal. Un API gateway cu logging centralizat ajută la inventarierea traficului real, dar nu înlocuiește documentația.
- Introspection activ în producție pentru GraphQL. Introspection permite oricui să descarce schema completă a API-ului, inclusiv câmpurile deprecate și relațiile interne. Dezactivează-l în producție sau restricționează-l la clienți autentificați. Monitorizează cererile de introspection în stack-ul de observabilitate pentru a detecta eventuale tentative de cartografiere a API-ului.
Întrebări frecvente
REST și GraphQL se pot folosi în același proiect?
Da, dar numai cu un motiv clar pentru fiecare în parte. O abordare comună este REST pentru autentificare și operații CRUD simple, GraphQL pentru un layer de date cu cerințe de query flexibile. Fără motivație explicită, combini complexitățile ambelor fără să câștigi beneficiile complete ale niciunuia.
GraphQL rezolvă problema over-fetching-ului din REST?
Da, dar introduce problema N+1 dacă nu implementezi DataLoader. Clientul cere exact câmpurile vrute. Prețul este că serverul trebuie să rezolve fiecare câmp, iar câmpurile relaționate generează query-uri în buclă dacă nu sunt grupate explicit prin batching.
Este GraphQL mai rapid decât REST?
Nu în mod implicit; depinde de implementare. GraphQL reduce round-trip-urile, dar query-urile complexe costă mai mult pe server. REST cu caching HTTP nativ este mai rapid pentru date care nu se schimbă des.
Cum se protejează un API GraphQL de query-uri abuzive?
Prin cost analysis și depth limiting înainte de execuție. Un query GraphQL recursiv poate supraîncărca serverul fără să atingă un endpoint explicit. Bibliotecile mature (graphql-java, graphene) oferă mecanisme de limitare. Fără acestea, rate limiting la nivel de rețea nu este suficient.
Pot face versionare la un API GraphQL ca la REST?
Convenția în GraphQL este să deprecezi câmpuri și să adaugi altele noi, nu să faci versionare explicită. Schema este aditivă: adaugi câmpuri noi, marchezi cele vechi ca deprecated. REST face versionare prin URL sau header; GraphQL evoluează schema în același endpoint.