Najbolji postupci za rukovanje pogreškama API-ja REST

1. Uvod

REST je arhitektura bez državljanstva u kojoj klijenti mogu pristupiti resursima na poslužitelju i njima upravljati. Općenito, REST usluge koriste HTTP za oglašavanje skupa resursa kojima upravljaju i pružaju API koji omogućava klijentima da dobiju ili promijene stanje tih resursa.

U ovom ćemo uputstvu naučiti neke od najboljih praksi za rukovanje pogreškama REST API-ja, uključujući korisne pristupe pružanju relevantnih informacija korisnicima, primjere s velikih web lokacija i konkretnu implementaciju pomoću primjera Spring REST aplikacije.

2. HTTP statusni kodovi

Kada klijent uputi zahtjev HTTP poslužitelju - a poslužitelj uspješno primi zahtjev - poslužitelj mora obavijestiti klijenta je li zahtjev uspješno obrađen ili nije. HTTP to postiže s pet kategorija statusnih kodova:

  • 100-razina (informativno) - poslužitelj prihvaća zahtjev
  • 200-razina (uspješno) - poslužitelj je ispunio zahtjev kako se očekivalo
  • 300-razina (preusmjeravanje) - Klijent treba izvršiti daljnje radnje da bi dovršio zahtjev
  • 400-razina (pogreška klijenta) - klijent je poslao nevažeći zahtjev
  • 500-razina (pogreška poslužitelja) - poslužitelj nije uspio ispuniti valjani zahtjev zbog pogreške s poslužiteljem

Na temelju koda odgovora, klijent može pretpostaviti rezultat određenog zahtjeva.

3. Rukovanje pogreškama

Prvi korak u rješavanju pogrešaka je pružanje klijentu odgovarajućeg statusnog koda. Uz to, možda ćemo trebati pružiti više informacija u odgovornom tijelu.

3.1. Osnovni odgovori

Najjednostavniji način na koji rješavamo pogreške je odgovorite odgovarajućim statusnim kodom.

Neki uobičajeni kodovi odgovora uključuju:

  • 400 Loš zahtjev - Klijent je poslao nevaljani zahtjev - poput nedostatka potrebnog tijela zahtjeva ili parametra
  • 401 Neovlašteno - Klijent nije uspio provjeriti autentičnost s poslužiteljem
  • 403 Zabranjeno - Klijent je ovjeren, ali nema dozvolu za pristup traženom resursu
  • 404 Not Found - Zatraženi resurs ne postoji
  • 412 Preduvjet nije uspio - Jedan ili više uvjeta u poljima zaglavlja zahtjeva ocijenjeno je kao netačno
  • 500 Interna pogreška poslužitelja - Na poslužitelju se dogodila generička pogreška
  • 503 Usluga nije dostupna - tražena usluga nije dostupna

Iako su osnovni, ovi kodovi omogućavaju klijentu da shvati široku prirodu pogreške koja se dogodila. Na primjer, znamo ako primimo pogrešku 403 da nam nedostaju dozvole za pristup resursu koji smo zatražili.

U mnogim slučajevima, međutim, u odgovorima moramo navesti dodatne pojedinosti.

500 pogrešaka signalizira da su se na poslužitelju pojavili neki problemi ili iznimke tijekom obrade zahtjeva. Općenito, ova interna pogreška nije stvar našeg klijenta.

Stoga, da bismo minimalizirali takvu vrstu odgovora na klijenta, trebali bismo marljivo pokušavati riješiti ili uhvatiti interne pogreške i odgovoriti drugim odgovarajućim statusnim kodovima kad god je to moguće. Na primjer, ako se dogodi iznimka jer zatraženi resurs ne postoji, trebali bismo to izložiti kao pogrešku 404, a ne kao 500.

To ne znači da se 500 nikada ne smije vratiti, već samo da se koristi za neočekivane uvjete - poput prekida usluge - koji sprečavaju poslužitelj da izvrši zahtjev.

3.2. Zadani odgovori na proljetnu pogrešku

Ti su principi toliko sveprisutni da ih je Spring kodificirao u svom zadanom mehanizmu za rukovanje pogreškama.

Da bismo demonstrirali, pretpostavimo da imamo jednostavnu Spring REST aplikaciju koja upravlja knjigama, s krajnjom točkom za dohvaćanje knjige prema njezinom ID-u:

curl -X GET -H "Accept: application / json" // localhost: 8082 / spring-rest / api / book / 1

Ako ne postoji knjiga s ID-om 1, očekujemo da će naš kontrolor baciti a BookNotFoundException. Izvođenjem GET-a na ovoj krajnjoj točki vidimo da je izuzetak izbačen i tijelo odgovora je:

{"timestamp": "2019-09-16T22: 14: 45.624 + 0000", "status": 500, "error": "Interna pogreška poslužitelja", "message": "Nije dostupna poruka", "path": " / api / book / 1 "}

Imajte na umu da ovaj zadani obrađivač pogrešaka uključuje vremensku oznaku kada se pogreška dogodila, HTTP kod statusa, naslov ( pogreška polje), poruku (koja je prema zadanim postavkama prazna) i putanju URL-a na kojoj se dogodila pogreška.

Ta polja pružaju klijentu ili programeru informacije za pomoć u rješavanju problema a također čine nekoliko polja koja čine standardni mehanizmi za rukovanje pogreškama.

Uz to, imajte na umu da Spring automatski vraća HTTP statusni kôd 500 kada je naš BookNotFoundException baca se. Iako će neki API-ji vratiti statusni kod 500 ili neki drugi generički, kao što ćemo vidjeti kod Facebook-a i Twitter-a - za sve pogreške radi jednostavnosti, najbolje je koristiti najspecifičniji kôd pogreške kad god je to moguće.

U našem primjeru možemo dodati a @ControllerAdvice tako da kad a BookNotFoundException bačen, naš API vraća status 404 za označavanje Nije pronađeno umjesto 500 Interna pogreška poslužitelja.

3.3. Detaljniji odgovori

Kao što se vidi u gornjem primjeru Proljeća, ponekad statusni kôd nije dovoljan da pokaže specifičnosti pogreške. Po potrebi možemo koristiti tijelo odgovora kako bismo klijentu pružili dodatne informacije. Kada pružamo detaljne odgovore, trebali bismo uključiti:

  • Pogreška - jedinstveni identifikator pogreške
  • Poruka - kratka čovjeku čitljiva poruka
  • Pojedinosti - Dulje objašnjenje pogreške

Na primjer, ako klijent pošalje zahtjev s netočnim vjerodajnicama, možemo poslati odgovor 401 s tijelom:

{"error": "auth-0001", "message": "Netočno korisničko ime i lozinka", "detail": "Provjerite jesu li korisničko ime i lozinka uključeni u zahtjev točni"}

The pogreška polje ne bi trebalo odgovarati kodu odgovora. Umjesto toga, to bi trebao biti kôd pogreške jedinstven za našu aplikaciju. Općenito, ne postoji konvencija za pogreška polje, očekujte da bude jedinstveno.

Ovo polje obično sadrži samo alfanumeričke znakove i povezujuće znakove, poput crtica ili donjih crta. Na primjer, 0001, auth-0001, i netočno-prolazak korisnika su kanonski primjeri kodova pogrešaka.

The poruka Dio tijela obično se smatra predstavljivim na korisničkim sučeljima. Stoga bismo trebali prevesti ovaj naslov ako podržavamo internacionalizaciju. Dakle, ako klijent pošalje zahtjev s Prihvati-jezik zaglavlje koje odgovara francuskom, titula vrijednost treba prevesti na francuski.

The detalj Dio je namijenjen programerima klijenata, a ne krajnjem korisniku, tako da prijevod nije potreban.

Uz to bismo mogli pružiti i URL - poput Pomozite polje - koje klijenti mogu slijediti kako bi otkrili više informacija:

{"error": "auth-0001", "message": "Netočno korisničko ime i lozinka", "detail": "Provjerite jesu li korisničko ime i lozinka uključeni u zahtjev točni", "help": "// primjer. com / help / error / auth-0001 "}

Ponekad, možda ćemo htjeti prijaviti više pogrešaka za zahtjev. U tom bismo slučaju trebali vratiti pogreške s popisa:

{"error": [{"error": "auth-0001", "message": "Netočno korisničko ime i lozinka", "detail": "Provjerite jesu li korisničko ime i lozinka uključeni u zahtjev točni", "help" : "//example.com/help/error/auth-0001"}, ...]}

A kada se dogodi jedna pogreška, odgovaramo popisom koji sadrži jedan element. Imajte na umu da je odgovor s više pogrešaka možda prekompliciran za jednostavne aplikacije. U mnogim je slučajevima dovoljno odgovoriti prvom ili najznačajnijom pogreškom.

3.4. Standardizirana tijela za odgovor

Iako se većina REST API-ja pridržava sličnih konvencija, specifičnosti se obično razlikuju, uključujući nazive polja i informacije uključene u tijelo odgovora. Te razlike otežavaju knjižnicama i okvirima jednoobrazno postupanje s pogreškama.

U nastojanju da standardizira REST API postupanje s pogreškama, IETF je osmislio RFC 7807, koji stvara generaliziranu shemu za rješavanje pogrešaka.

Ova se shema sastoji od pet dijelova:

  1. tip - URI identifikator koji kategorizira pogrešku
  2. titula - Kratka, čovjeku čitljiva poruka o pogrešci
  3. status - Kôd HTTP odgovora (nije obavezno)
  4. detalj - Čitljivo objašnjenje pogreške
  5. primjer - URI koji identificira određenu pojavu pogreške

Umjesto da koristimo naše prilagođeno tijelo za odgovor na pogrešku, svoje tijelo možemo pretvoriti u:

{"type": "/ pogreške / netočna-korisnička lozinka", "title": "Pogrešno korisničko ime ili lozinka.", "status": 401, "detail": "Autentifikacija nije uspjela zbog netočnog korisničkog imena ili lozinke.", "instance": "/ login / log / abc123"}

Imajte na umu da tip polje kategorizira vrstu pogreške, dok primjer identificira specifičnu pojavu pogreške na sličan način kao klase odnosno objekti.

Korištenjem URI-a klijenti mogu slijediti ove putove kako bi pronašli više informacija o pogrešci na isti način na koji se veze HATEOAS mogu koristiti za navigaciju REST API-jem.

Pridržavanje RFC 7807 nije obavezno, ali je korisno ako se želi ujednačenost.

4. Primjeri

Gore navedeni postupci uobičajeni su u nekim od najpopularnijih REST API-ja. Iako se određeni nazivi polja ili formati mogu razlikovati među web lokacijama, opći su obrasci gotovo univerzalni.

4.1. Cvrkut

Na primjer, pošaljite GET zahtjev bez davanja potrebnih podataka za provjeru autentičnosti:

curl -X GET //api.twitter.com/1.1/statuses/update.json?include_entities=true

Twitter API s pogreškom odgovara sljedećim tijelom:

{"error": [{"code": 215, "message": "Loši podaci za provjeru autentičnosti." }]}

Ovaj odgovor uključuje popis koji sadrži jednu pogrešku, sa svojim kodom pogreške i porukom. U Twitterovom slučaju nije prisutna detaljna poruka i općenita pogreška - umjesto konkretnije pogreške 401 - koristi se da označi da provjera autentičnosti nije uspjela.

Ponekad je općenitiji statusni kod lakši za primjenu, kao što ćemo vidjeti u našem primjeru za proljeće u nastavku. Omogućuje programerima da uhvate skupine iznimaka i ne razlikuju statusni kôd koji treba vratiti. Kad god je to moguće, treba koristiti najspecifičniji statusni kod.

4.2. Facebook

Slično Twitteru, i Facebook Graph REST API u svoje odgovore uključuje detaljne informacije.

Na primjer, izvedimo POST zahtjev za provjeru autentičnosti s API-jem Facebook Graph:

curl -X GET //graph.facebook.com/oauth/access_token?client_id=foo&client_secret=bar&grant_type=baz

Primamo sljedeću pogrešku:

{"error": {"message": "Nedostaje parametar redirect_uri.", "type": "OAuthException", "code": 191, "fbtrace_id": "AWswcVwbcqfgrSgjG80MtqJ"}}

Kao i Twitter, Facebook također koristi generičku pogrešku - umjesto preciznije pogreške na 400 razina - da označi kvar. Uz poruku i numerički kod, Facebook uključuje i tip polje koje kategorizira pogrešku i ID traga (fbtrace_id) koji djeluje kao interni identifikator podrške.

5. Zaključak

U ovom smo članku ispitali neke od najboljih praksi upravljanja pogreškama REST API-a, uključujući:

  • Pružanje posebnih statusnih kodova
  • Uključujući dodatne informacije u tijela za odgovor
  • Rukovanje iznimkama na jedinstven način

Iako će se detalji rješavanja pogrešaka razlikovati ovisno o aplikaciji, ovi se opći principi primjenjuju na gotovo sve REST API-je i treba ih se pridržavati kad je to moguće.

To ne samo da omogućava klijentima da dosljedno postupaju s pogreškama, već i pojednostavljuje kôd koji stvaramo prilikom implementacije REST API-ja.

Kôd naveden u ovom članku dostupan je na GitHub-u.