REST: God praksis for API-design

Design dit REST-API, så det bliver brugt

af Jay Kapadnis, Tempus Arkitekt

Dårligt designet REST-API'er = FRUSTRATION

Arbejder som Tempus-udvikler og arkitekt, integrerer jeg med masser af tjenester gennem REST. Nogle gange synes jeg det er vanskeligt og tidskrævende at integrere / forbruge API'er på grund af dårlig design med næsten ingen dokumentation. Dette fører til, at udviklere (og mig) opgiver eksisterende tjenester og muligvis duplikerer funktionalitet. For at undgå denne frustration stræber ingeniørteamet på Hashmap efter at overholde specifikke standarder og specifikationer, der er fastlagt i eksisterende REST-standarder.

Lad os starte vores diskussion med først at forstå, hvad REST er, og hvad der menes med at designe REST-API'er.

Hvad er REST?

I 2000 foreslog Roy Fielding, en af ​​hovedforfatterne af HTTP-specifikationen, en arkitektonisk tilgang til design af webservices kendt som Representative State Transfer (REST).

Bemærk, at selvom denne artikel antager REST-implementering med HTTP-protokol, er REST ikke bundet til HTTP. REST API'er implementeres for en "ressource", der kan være en enhed eller en tjeneste. Disse API'er giver mulighed for at identificere en ressource ved dens URI, som kan bruges til at overføre en repræsentation af en ressource's aktuelle tilstand over HTTP.

Hvorfor er API-design så vigtig?

Folk stiller dette spørgsmål ganske meget, og for at besvare dette:

REST API'er er ansigtet på enhver tjeneste, og derfor bør de:

1. Vær let at forstå, så integrationen er ligetil
2. Vær veldokumenteret, så semantisk adfærd forstås (ikke kun syntaktisk)
3. Følg accepterede standarder som HTTP

Designe og udvikle meget nyttige REST API'er

Der er flere konventioner, vi følger på Hashmap, mens vi designer vores REST API'er, så vi sikrer, at vi lever op til de forventninger, der er anført ovenfor for vores acceleratorudvikling og vores konsulentopgaver.

Disse konventioner er som følger:

1. Brug substantiver i URI

REST API'er skal designes til ressourcer, der kan være enheder eller tjenester osv., Derfor skal de altid være navneord. For eksempel i stedet for / createUser brug / brugere

2. Flertalsform eller singularer

Generelt foretrækker vi at bruge flertal, men der er ingen hård regel, at man ikke kan bruge ental til ressourcenavn. Ideologien bag brugen af ​​flertal er:

Vi arbejder på en ressource fra indsamling af ressourcer, så for at skildre samling, vi bruger flertal

For eksempel i tilfælde af ...

GET / brugere / 123

klienten beder om at hente en ressource fra brugernes samling med id 123. Mens vi opretter en ressource, vil vi tilføje en ressource til den aktuelle samling af ressourcer, så API ser ud som nedenunder ...

POST / brugere

3. Lad HTTP-verb definere handling

Pr. Punkt 1 ovenfor skal API'er kun give substantiver til ressourcer og lade HTTP-verbene (GET, POST, PUT, DELETE) definere handlingen, der skal udføres på en ressource.

Tabellen nedenfor opsummerer brugen af ​​HTTP-verb sammen med API'er:

Tabel 1: HTTP-verb og brug

4. Brug ikke sikkerhedsmetoder (idempotency)

Sikre metoder er HTTP-metoder, der returnerer den samme ressourcerepræsentation uanset hvor mange gange der kaldes af klienten. GET, HEAD, OPTIONS og TRACE-metoder er defineret som sikre, hvilket betyder, at de kun er beregnet til at hente data og bør ikke ændre en ressourcetilstand på en server. Brug ikke GET til at slette indhold, for eksempel ...

GET / brugere / 123 / slet

Det er ikke sådan, at dette ikke kan implementeres, men HTTP-specifikationen overtrædes i dette tilfælde.

Brug HTTP-metoder i henhold til den handling, der skal udføres.

5. Vis ressourcehierarki gennem URI

Hvis en ressource indeholder underressourcer, skal du sørge for at afbilde dette i API'en for at gøre det mere eksplicit. For eksempel, hvis en bruger har indlæg, og vi ønsker at hente et specifikt indlæg af bruger, kan API defineres som GET / brugere / 123 / indlæg / 1, som vil hente indlæg med id 1 af bruger med id 123

6. Version dine API'er

Versionering af API'er hjælper altid med at sikre en bagudkompatibilitet af en tjeneste, mens du tilføjer nye funktioner eller opdaterer eksisterende funktionalitet til nye klienter. Der er forskellige tankeskoler til at version din API, men de fleste af dem falder ind under to kategorier nedenfor:

headers:

Der er 2 måder, du kan specificere version i overskrifter:

Tilpasset overskrift:

Tilføjelse af en brugerdefineret X-API-VERSION (eller en hvilken som helst anden header) -hovedtast efter klient kan bruges af en tjeneste til at rute en anmodning til det rigtige slutpunkt

Accepter overskrift

Brug accept-header til at specificere din version, f.eks

=> Accepter: applikation / vnd.hashmapinc.v2 + json

URL:

Integrer versionen i URL'en som f.eks

POST / v2 / brugere

Vi foretrækker at bruge URL-metode til versionering, da den giver en bedre synlighed af en ressource ved at se på URL-adressen. Nogle hævder muligvis, at URL refererer til den samme ressource uanset version, og da responsrepræsentation muligvis eller måske ikke ændres efter versionering, hvad er poenget med at have en anden URL til den samme ressource?

Jeg går ikke ind for en fremgangsmåde frem for en anden her, og i sidste ende skal udvikleren vælge deres foretrukne måde at vedligeholde versioner på.

7. Hjemrepræsentation

POST-, PUT- eller PATCH-metoder, der bruges til at oprette en ressource eller opdatere felter i en ressource, skal altid returnere opdateret ressourcerepræsentation som et svar med passende statuskode som beskrevet i yderligere punkter.

POST, hvis det lykkedes at tilføje ny ressource, skal returnere HTTP-statuskode 201 sammen med URI for den nyoprettede ressource i placeringshovedet (som pr. HTTP-specifikation)

8. Filtrer, søg og sorter

Opret ikke forskellige URI'er til hentning af ressourcer med filtrering, søgning eller sortering af parametre. Forsøg at holde URI enkel, og tilføj forespørgselsparametre for at skildre parametre eller kriterier for at hente en ressource (en enkelt type ressource)

filtrering:

Brug forespørgselsparametre defineret i URL til filtrering af en ressource fra serveren. For eksempel, hvis vi gerne vil hente alle offentliggjorte indlæg af bruger, kan du designe et API, f.eks:

GET / brugere / 123 / posts? State = publiceret

I eksemplet ovenfor er tilstand filterparameter

Søger:

For at få resultaterne med kraftfulde søgeforespørgsler i stedet for grundlæggende filtre, kunne man bruge flere parametre i en URI til at anmode om at hente en ressource fra serveren.

GET / brugere / 123 / posts? State = publiceret & ta = scala

Ovenstående forespørgsel søger efter indlæg, der er offentliggjort med Scala-tagget. Det er meget almindeligt i dag, at Solr bruges som søgeværktøj, da det giver avancerede muligheder for at søge efter et dokument, og du kan designe din API, såsom:

GET / brugere / 123 / stillinger? Q = sometext & fq = tilstand: publiceret, ta: scala

Dette vil søge indlæg efter fri tekst “sometext” (q) og filtrere resultater i fq-tilstand som offentliggjort og have tag Scala.

Sortering:

ASC- og DESC-sorteringsparametre kan videregives i URL, såsom:

GET / brugere / 123 / posts? Sort = -updated_at

Returnerer indlæg sorteret med faldende rækkefølge på tidspunktet for opdateringsdatoen.

9. HATEOAS

Hypermedia As Transfer Engine Of Application State er en begrænsning af REST-applikationsarkitekturen, der adskiller den fra andre netværksapplikationsarkitekturer.

Det giver nem navigering gennem en ressource og dens tilgængelige handlinger. På denne måde behøver en klient ikke vide, hvordan man interagerer med en applikation til forskellige handlinger, da alle metadata indlejres i svar fra serveren.

For at forstå det bedre, lad os se på nedenstående respons fra hent bruger med id 123 fra serveren:

{
“Navn”: “John Doe”,
"Links": [
{
"Rel": "selv",
“Href”: “http: // localhost: 8080 / brugere / 123”
},
{
"Rel": "indlæg",
“Href”: “http: // localhost: 8080 / brugere / 123 / indlæg”
},
{
"Rel": "adresse",
“Href”: “http: // localhost: 8080 / brugere / 123 / adresse”
}
]
}

Nogle gange er det lettere at springe over linkformatet og specificere links som felter i en ressource som nedenfor:

{
“Navn”: “John Doe”,
“Self”: “http: // localhost: 8080 / brugere / 123”,
“Indlæg”: “http: // localhost: 8080 / brugere / 123”,
“Adresse”: “http: // localhost: 8080 / brugere / 123 / adresse”
}

Det er ikke en konvention, du skal følge hver gang, da det afhænger af ressourcefelter / størrelse og handlinger, der kan udføres på ressource. Hvis ressourcer indeholder flere felter, som brugeren muligvis ikke ønsker at gennemgå, er det en god ide at vise navigation til underressourcer og derefter implementere HATEOAS.

10. Statsløs godkendelse og autorisation

REST-API'er skal være statsløse. Hver anmodning skal være selvforsynende og skal opfyldes uden kendskab til den forudgående anmodning. Dette sker i tilfælde af at godkende en brugerhandling.

Tidligere lagrede udviklere brugerinformation i serversidesessioner, hvilket ikke er en skalerbar tilgang. Af denne grund skal enhver anmodning indeholde alle brugernes oplysninger (hvis det er et sikkert API) i stedet for at stole på tidligere anmodninger.

Dette begrænser ikke API'er til en bruger som en autoriseret person, da det også giver tilladelse til service til service. For brugertilladelse giver JWT (JSON Web Token) med OAuth2 en måde at opnå dette på. Til service til service-kommunikation skal du prøve at få den krypterede API-nøgle sendt i overskriften.

11. Swagger til dokumentation

Swagger er et vidt brugt værktøj til at dokumentere REST API'er, der giver en måde at udforske brugen af ​​et specifikt API og derfor giver udviklere mulighed for at forstå den underliggende semantiske opførsel. Det er en erklærende måde at tilføje dokumentation ved hjælp af kommentarer, der yderligere genererer en JSON, der beskriver API'er og deres anvendelse.

Vi har oprettet en Maven Archetype, som kan komme i gang her: Maven Archetype.

12. HTTP-statuskoder

Brug HTTP-statuskoder til at give svaret til en klient. Det kan være en succes- eller fiaskosvar, men det bør definere, hvad den respektive succes eller fiasko betyder fra et serverperspektiv.

Nedenfor er kategorierne af svar efter deres statuskoder:

2xx succes

200 OK: Returneres ved en vellykket GET- eller SLET-handling. PUT eller POST kan også bruge dette, hvis tjenesten ikke ønsker at returnere en ressource tilbage til klienten efter oprettelse eller ændring.

201 Oprettet: Svar for en vellykket ressourceoprettelse ved en POST-anmodning.

3xx omdirigering

304 Ikke ændret: Bruges, hvis HTTP-cachehoved er implementeret.

4xx klientfejl

400 dårlig anmodning: Når et HTTP-anmodningsorgan ikke kan analyseres. For eksempel, hvis en API forventer et organ i et JSON-format til en POST-anmodning, men kroppen af ​​anmodningen er forkert.

401 Uautoriseret: Autentificering er ikke succesrig (eller der er ikke givet legitimationsoplysninger) under adgang til API'et.

403 forbudt: Hvis en bruger ikke er autoriseret til at udføre en handling, selvom godkendelsesoplysninger er korrekte.

404 Ikke fundet: Hvis den anmodede ressource ikke er tilgængelig på serveren.

405 Metode ikke tilladt: Hvis brugeren forsøger at overtræde en API-kontrakt, f.eks. Forsøger at opdatere en ressource ved hjælp af en POST-metode.

5xx serverfejl

Disse fejl opstår på grund af serverfejl eller problemer med den underliggende infrastruktur.

Afslutter

Udviklere er nødt til at bruge lidt tid på at designe REST API'er, da API'en kan gøre en service meget let at bruge eller ekstremt kompleks. Derudover kan modenheden for API'erne let dokumenteres ved hjælp af Richardson Maturity Model.

Hvis du gerne vil dele dine tanker om integration med REST-tjenester og forstå mere om, hvad jeg arbejder med dagligt med Tempus eller planlægge en demonstration, skal du kontakte mig på jay.kapadnis@hashmapinc.com.

Du er velkommen til at dele på tværs af andre kanaler, og vær sikker og følg med med alt nyt indhold fra Hashmap på https://medium.com/hashmapinc.

Jay Kapadnis er Tempus-arkitekt hos Hashmap, der arbejder på ingeniørholdet på tværs af brancher med en gruppe innovative teknologer og domæneeksperter, der fremskynder forretningsværdier med høj værdi for vores kunder.