Beste fremgangsmåter for REST API-feilhåndtering

1. Introduksjon

REST er en statsløs arkitektur der klienter kan få tilgang til og manipulere ressurser på en server. Generelt bruker REST-tjenester HTTP for å annonsere et sett med ressurser som de administrerer, og gir et API som gjør det mulig for klienter å skaffe eller endre tilstanden til disse ressursene.

I denne opplæringen lærer vi om noen av de beste metodene for å håndtere REST API-feil, inkludert nyttige tilnærminger for å gi brukerne relevant informasjon, eksempler fra store nettsteder og en konkret implementering ved hjelp av et eksempel på Spring REST-applikasjon.

2. HTTP-statuskoder

Når en klient gjør en forespørsel til en HTTP-server - og serveren mottar forespørselen - serveren må varsle klienten om forespørselen ble behandlet eller ikke. HTTP oppnår dette med fem kategorier av statuskoder:

  • 100-nivå (Informasjon) - Server bekrefter en forespørsel
  • 200-nivå (suksess) - Server fullførte forespørselen som forventet
  • 300-nivå (omdirigering) - Kunden må utføre ytterligere handlinger for å fullføre forespørselen
  • 400-nivå (klientfeil) - klienten sendte en ugyldig forespørsel
  • 500-nivå (serverfeil) - Serveren oppfylte ikke en gyldig forespørsel på grunn av en feil med serveren

Basert på responskoden, kan en klient anta resultatet av en bestemt forespørsel.

3. Håndteringsfeil

Det første trinnet i håndtering av feil er å gi en klient en riktig statuskode. I tillegg kan det hende vi trenger å gi mer informasjon i responsorganet.

3.1. Grunnleggende svar

Den enkleste måten vi håndterer feil på er å svare med en passende statuskode.

Noen vanlige svarskoder inkluderer:

  • 400 Dårlig forespørsel - Kunden sendte en ugyldig forespørsel - for eksempel mangler den nødvendige forespørselen eller parameter
  • 401 Uautorisert - Klienten klarte ikke å autentisere med serveren
  • 403 Forbidden - Klientautentisert, men har ikke tillatelse til å få tilgang til den forespurte ressursen
  • 404 Ikke funnet - Den etterspurte ressursen eksisterer ikke
  • 412 Forutsetning mislyktes - En eller flere forhold i forespørselens overskriftsfelt evaluert til falske
  • 500 intern serverfeil - Det oppstod en generell feil på serveren
  • 503 Tjeneste utilgjengelig - Den etterspurte tjenesten er ikke tilgjengelig

Mens de er enkle, tillater disse kodene en klient å forstå den brede arten av feilen som oppstod. For eksempel vet vi om vi mottar en 403-feil at vi mangler tillatelse til å få tilgang til ressursen vi ba om.

I mange tilfeller må vi imidlertid gi ytterligere detaljer i svarene våre.

500 feil signaliserer at noen problemer eller unntak oppstod på serveren under behandling av en forespørsel. Generelt sett er denne interne feilen ikke vår kundes virksomhet.

Derfor, for å minimere slike svar til klienten, vi bør flittig forsøke å håndtere eller fange interne feil og svare med andre passende statuskoder der det er mulig. For eksempel, hvis et unntak oppstår fordi en ønsket ressurs ikke eksisterer, bør vi avsløre dette som en 404-snarere enn en 500-feil.

Dette er ikke å si at 500 aldri skal returneres, bare at den skal brukes til uventede forhold - for eksempel et tjenesteavbrudd - som hindrer serveren i å utføre forespørselen.

3.2. Standard vårfeilrespons

Disse prinsippene er så allestedsnærværende at Spring har kodifisert dem i sin standard feilhåndteringsmekanisme.

For å demonstrere, antar vi at vi har et enkelt Spring REST-program som administrerer bøker, med et sluttpunkt for å hente en bok etter ID:

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

Hvis det ikke er noen bok med ID 1, forventer vi at kontrolleren vår vil kaste et BookNotFoundException. Når vi utfører en GET på dette endepunktet, ser vi at dette unntaket ble kastet, og responsorganet er:

{"tidsstempel": "2019-09-16T22: 14: 45.624 + 0000", "status": 500, "error": "Intern serverfeil", "message": "Ingen melding tilgjengelig", "path": " / api / book / 1 "}

Merk at denne standard feilbehandleren inkluderer en tidsstempel for når feilen oppstod, HTTP-statuskoden, en tittel (den feil felt), en melding (som er tom som standard) og URL-banen der feilen oppstod.

Disse feltene gir en klient eller utvikler informasjon for å feilsøke problemet og utgjør også noen få av feltene som utgjør standard feilhåndteringsmekanismer.

Vær også oppmerksom på at Spring automatisk returnerer en HTTP-statuskode på 500 når vår BookNotFoundException blir kastet. Selv om noen API-er vil returnere en 500-statuskode eller andre generiske, som vi vil se med Facebook- og Twitter-APIene - for alle feil for enkelhets skyld, det er best å bruke den mest spesifikke feilkoden når det er mulig.

I vårt eksempel kan vi legge til en @ControllerAdvice slik at når en BookNotFoundException kastes, gir API-en vår tilbake statusen 404 å betegne Ikke funnet i stedet for 500 intern server feil.

3.3. Mer detaljerte svar

Som vist i våreksempelet ovenfor, er det noen ganger ikke nok med en statuskode for å vise detaljene i feilen. Når det er nødvendig, kan vi bruke svaret til å gi klienten ytterligere informasjon. Når du gir detaljerte svar, bør vi inkludere:

  • Feil - En unik identifikator for feilen
  • Melding - En kort melding som kan leses av mennesker
  • Detalj - En lengre forklaring på feilen

For eksempel, hvis en klient sender en forespørsel med feil legitimasjon, kan vi sende et 401-svar med en kropp på:

{"error": "auth-0001", "message": "Feil brukernavn og passord", "detalj": "Forsikre deg om at brukernavnet og passordet som er inkludert i forespørselen er riktige"}

De feil -feltet skal ikke matche svarskoden. I stedet bør det være en feilkode som er unik for applikasjonen vår. Generelt er det ingen konvensjon for feil felt, forvent at det er unikt.

Vanligvis inneholder dette feltet bare alfanumerikk og tilknytningstegn, for eksempel bindestreker eller understrekninger. For eksempel, 0001, auth-0001, og feil brukerpass er kanoniske eksempler på feilkoder.

De beskjed en del av kroppen anses vanligvis å være presentabel i brukergrensesnittene. Derfor bør vi oversette denne tittelen hvis vi støtter internasjonalisering. Så hvis en klient sender en forespørsel med en Godta-språk topptekst som tilsvarer fransk, den tittel verdi bør oversettes til fransk.

De detalj delen er ment for bruk av klientutviklere og ikke sluttbrukeren, så oversettelsen er ikke nødvendig.

I tillegg kan vi også oppgi en URL - for eksempel hjelp felt - som klienter kan følge for å oppdage mer informasjon:

{"error": "auth-0001", "message": "Feil brukernavn og passord", "detalj": "Forsikre deg om at brukernavnet og passordet som er inkludert i forespørselen er riktige", "help": "// eksempel. no / hjelp / feil / auth-0001 "}

Noen ganger, Det kan være lurt å rapportere mer enn én feil for en forespørsel. I dette tilfellet bør vi returnere feilene i en liste:

{"feil": [{"feil": "auth-0001", "message": "Feil brukernavn og passord", "detalj": "Forsikre deg om at brukernavnet og passordet som er inkludert i forespørselen er riktige", "hjelp" : "//eksempel.com/hjelp/feil/auth-0001"}, ...]}

Og når det oppstår en enkelt feil, svarer vi med en liste som inneholder ett element. Merk at å svare med flere feil kan være for komplisert for enkle applikasjoner. I mange tilfeller er det tilstrekkelig å svare med den første eller mest betydningsfulle feilen.

3.4. Standardiserte responsorganer

Mens de fleste REST APIer følger lignende konvensjoner, varierer spesifikasjonene vanligvis, inkludert navn på felt og informasjonen som er inkludert i responsorganet. Disse forskjellene gjør det vanskelig for biblioteker og rammer å håndtere feil jevnt.

I et forsøk på å standardisere REST API-feilhåndtering, IETF utviklet RFC 7807, som skaper et generalisert feilhåndteringsskjema.

Dette skjemaet består av fem deler:

  1. type - En URI-identifikator som kategoriserer feilen
  2. tittel - En kort, menneskelig lesbar melding om feilen
  3. status - HTTP-responskoden (valgfritt)
  4. detalj - En menneskelig lesbar forklaring på feilen
  5. forekomst - En URI som identifiserer den spesifikke forekomsten av feilen

I stedet for å bruke vårt tilpassede feilresponsorgan, kan vi konvertere kroppen vår til:

{"type": "/ errors / incorrect-user-pass", "title": "Feil brukernavn eller passord.", "status": 401, "detalj": "Autentisering mislyktes på grunn av feil brukernavn eller passord.", "forekomst": "/ login / log / abc123"}

Merk at type felt kategoriserer feiltypen, mens forekomst identifiserer en spesifikk forekomst av feilen på en lignende måte som henholdsvis klasser og objekter.

Ved å bruke URI-er kan klienter følge disse banene for å finne mer informasjon om feilen på samme måte som HATEOAS-lenker kan brukes til å navigere i et REST API.

Overholdelse av RFC 7807 er valgfritt, men det er fordelaktig hvis ensartethet ønskes.

4. Eksempler

Ovennevnte fremgangsmåter er vanlige i noen av de mest populære REST API-ene. Mens de spesifikke navnene på felt eller formater kan variere mellom nettsteder, de generelle mønstrene er nesten universelle.

4.1. Twitter

La oss for eksempel sende en GET-forespørsel uten å oppgi de nødvendige autentiseringsdataene:

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

Twitter API svarer med en feil med følgende kropp:

{"feil": [{"kode": 215, "melding": "Dårlig godkjenningsdata." }]}

Dette svaret inkluderer en liste som inneholder en enkelt feil, med feilkode og melding. I Twitters tilfelle er ingen detaljert melding til stede, og en generell feil - i stedet for en mer spesifikk 401-feil - brukes til å betegne at autentisering mislyktes.

Noen ganger er en mer generell statuskode lettere å implementere, som vi får se i våreksempelet nedenfor. Det lar utviklere fange grupper med unntak og ikke skille statuskoden som skal returneres. Når det er mulig, skjønt den mest spesifikke statuskoden skal brukes.

4.2. Facebook

I likhet med Twitter inkluderer Facebooks Graph REST API også detaljert informasjon i svarene.

La oss for eksempel utføre en POST-forespørsel om å autentisere med Facebook Graph API:

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

Vi får følgende feil:

{"error": {"message": "Mangler redirect_uri-parameter.", "type": "OAuthException", "code": 191, "fbtrace_id": "AWswcVwbcqfgrSgjG80MtqJ"}}

Som Twitter bruker Facebook også en generisk feil - snarere enn en mer spesifikk 400-nivå feil - for å betegne en feil. I tillegg til en melding og numerisk kode, inkluderer Facebook også en type felt som kategoriserer feilen og en spor-ID (fbtrace_id) som fungerer som en intern støtteidentifikator.

5. Konklusjon

I denne artikkelen undersøkte vi noen av de beste metodene for REST API-feilhåndtering, inkludert:

  • Gi spesifikke statuskoder
  • Inkludert tilleggsinformasjon i responsorganer
  • Håndtering av unntak på en enhetlig måte

Selv om detaljene for feilhåndtering vil variere etter applikasjon, disse generelle prinsippene gjelder nesten alle REST APIer og bør følges når det er mulig.

Ikke bare lar dette klienter håndtere feil på en jevn måte, men det forenkler også koden vi lager når vi implementerer et REST API.

Koden det er referert til i denne artikkelen er tilgjengelig på GitHub.