REST: Good Practices voor API-ontwerp

Ontwerp uw REST API zodat deze zal wennen

door Jay Kapadnis, Tempus Architect

Slecht ontworpen REST API's = FRUSTRATIE

Werkend als Tempus-ontwikkelaar en architect, integreer ik met veel services via REST. Soms vind ik het moeilijk en tijdrovend om API's te integreren / consumeren vanwege een slecht ontwerp met weinig tot geen documentatie. Dit leidt ertoe dat ontwikkelaars (en ik) bestaande services verlaten en mogelijk dubbele functionaliteit gebruiken. Om deze frustratie te voorkomen, streeft het engineeringteam van Hashmap ernaar zich te houden aan specifieke normen en specificaties die zijn vastgelegd in bestaande REST-normen.

Laten we onze discussie beginnen door eerst te begrijpen wat REST is en wat wordt bedoeld met het ontwerpen van REST API's.

Wat is REST?

In 2000 stelde Roy Fielding, een van de belangrijkste auteurs van de HTTP-specificatie, een architecturale benadering voor het ontwerpen van webservices bekend als Representational State Transfer (REST).

Hoewel dit artikel uitgaat van REST-implementatie met HTTP-protocol, is REST niet gebonden aan HTTP. REST API's zijn geïmplementeerd voor een "resource" die een entiteit of service kan zijn. Deze API's bieden een manier om een ​​bron te identificeren aan de hand van de URI, die kan worden gebruikt om een ​​representatie van de huidige status van een bron over te dragen via HTTP.

Waarom is API-ontwerp zo belangrijk?

Mensen stellen deze vraag vrij veel, en om dit te beantwoorden:

REST API's zijn het gezicht van elke service en daarom moeten ze:

1. Wees gemakkelijk te begrijpen, zodat integratie eenvoudig is
2. Wees goed gedocumenteerd, zodat semantisch gedrag wordt begrepen (niet alleen syntactisch)
3. Volg geaccepteerde standaarden zoals HTTP

Zeer nuttige REST API's ontwerpen en ontwikkelen

Er zijn verschillende conventies die we volgen bij Hashmap bij het ontwerpen van onze REST API's, zodat we ervoor zorgen dat we voldoen aan de hierboven vermelde verwachtingen voor onze ontwikkeling van de versneller en onze adviesopdrachten.

Deze conventies zijn als volgt:

1. Gebruik zelfstandige naamwoorden in URI

REST API's moeten worden ontworpen voor bronnen, die entiteiten of services, enz. Kunnen zijn, daarom moeten ze altijd zelfstandige naamwoorden zijn. Bijvoorbeeld in plaats van / createUser use / users

2. Meervoud of enkelvoud

Over het algemeen geven we er de voorkeur aan om meervoudsvormen te gebruiken, maar er is geen harde regel dat men geen enkelvoud kan gebruiken voor de bronnaam. De ideologie achter het gebruik van meervouden is:

We werken met één bron uit de verzameling bronnen, dus om de verzameling af te beelden gebruiken we meervoud

Bijvoorbeeld in het geval van ...

GET / gebruikers / 123

de client vraagt ​​om een ​​bron op te halen uit de gebruikersverzameling met id 123. Tijdens het maken van een bron willen we één bron toevoegen aan de huidige verzameling bronnen, dus de API ziet er als volgt uit ...

POST / gebruikers

3. Laat het HTTP-werkwoord actie definiëren

Volgens punt # 1 hierboven, mogen API's alleen zelfstandige naamwoorden voor bronnen bieden en de HTTP-werkwoorden (GET, POST, PUT, DELETE) de actie laten uitvoeren die op een resource moet worden uitgevoerd.

De onderstaande tabel vat het gebruik van HTTP-werkwoorden samen met API's samen:

Tabel 1: HTTP-werkwoorden en gebruik

4. Misbruik geen veilige methoden (idempotentie)

Veilige methoden zijn HTTP-methoden die dezelfde bronrepresentatie retourneren, ongeacht hoe vaak door de client wordt aangeroepen. GET-, HEAD-, OPTIONS- en TRACE-methoden worden als veilig gedefinieerd, wat betekent dat ze alleen zijn bedoeld voor het ophalen van gegevens en dat de status van een bron op een server niet mag worden gewijzigd. Gebruik GET niet om inhoud te verwijderen, bijvoorbeeld ...

GET / gebruikers / 123 / verwijderen

Het is niet alsof dit niet kan worden geïmplementeerd, maar HTTP-specificatie wordt in dit geval geschonden.

Gebruik HTTP-methoden volgens de actie die moet worden uitgevoerd.

5. Geef bronhiërarchie weer via URI

Als een resource subresources bevat, moet u deze in de API weergeven om deze explicieter te maken. Als een gebruiker bijvoorbeeld berichten heeft en we een specifiek bericht per gebruiker willen ophalen, kan API worden gedefinieerd als GET / users / 123 / posts / 1 die bericht met id 1 ophaalt door gebruiker met id 123

6. Versie uw API's

Versie-API's helpen altijd om achterwaartse compatibiliteit van een service te garanderen, terwijl nieuwe functies worden toegevoegd of bestaande functionaliteit wordt bijgewerkt voor nieuwe clients. Er zijn verschillende denkrichtingen om uw API te versieren, maar de meeste vallen onder twee categorieën hieronder:

headers:

Er zijn 2 manieren om een ​​versie in headers op te geven:

Aangepaste koptekst:

Het toevoegen van een aangepaste X-API-VERSIE (of een willekeurige andere header) naar keuze door de client kan door een service worden gebruikt om een ​​verzoek naar het juiste eindpunt te routeren

Koptekst accepteren

Gebruik koptekst accepteren om uw versie zoals op te geven

=> Accepteren: applicatie / vnd.hashmapinc.v2 + json

URL:

Sluit de versie in de URL in zoals

POST / v2 / gebruikers

We geven de voorkeur aan de URL-methode voor versiebeheer, omdat deze de vindbaarheid van een bron verbetert door naar de URL te kijken. Sommigen beweren dat URL naar dezelfde bron verwijst, ongeacht de versie en aangezien de weergave van de respons al dan niet kan veranderen na versiebeheer, wat is dan het nut van een andere URL voor dezelfde bron?

Ik pleit hier niet voor de ene aanpak boven de andere, en uiteindelijk moet de ontwikkelaar de manier kiezen waarop hij de versies bijhoudt.

7. Retourvertegenwoordiging

POST-, PUT- of PATCH-methoden, die worden gebruikt om een ​​resource te maken of velden in een resource bij te werken, moeten altijd bijgewerkte resource-weergave retourneren als een reactie met de juiste statuscode zoals beschreven in verdere punten.

POST als het lukt om een ​​nieuwe bron toe te voegen, moet de HTTP-statuscode 201 worden geretourneerd samen met de URI van de nieuwe bron in de locatiekop (volgens de HTTP-specificatie)

8. Filteren, zoeken en sorteren

Maak geen verschillende URI's voor het ophalen van bronnen met filter-, zoek- of sorteerparameters. Probeer de URI eenvoudig te houden en voeg queryparameters toe om parameters of criteria weer te geven om een ​​resource op te halen (één type resource)

Het filteren:

Gebruik queryparameters die in URL zijn gedefinieerd voor het filteren van een bron van de server. Als we bijvoorbeeld alle gepubliceerde berichten per gebruiker willen ophalen, kunt u een API ontwerpen zoals:

GET / gebruikers / 123 / berichten? Staat = gepubliceerd

In het bovenstaande voorbeeld is status de filterparameter

Zoeken:

Om de resultaten te krijgen met krachtige zoekopdrachten in plaats van basisfilters, zou men meerdere parameters in een URI kunnen gebruiken om te vragen om een ​​bron van de server op te halen.

GET / gebruikers / 123 / posts? State = gepubliceerd & ta = scala

De bovenstaande zoekopdracht zoekt naar berichten die zijn gepubliceerd met de Scala-tag. Het is tegenwoordig heel gebruikelijk dat Solr als zoekhulpmiddel wordt gebruikt, omdat het geavanceerde mogelijkheden biedt om naar een document te zoeken en u uw API kunt ontwerpen, zoals:

GET / gebruikers / 123 / berichten? Q = sometext & fq = status: gepubliceerd, ta: scala

Dit zal berichten zoeken naar vrije tekst "sometext" (q) en de resultaten filteren op fq-status zoals gepubliceerd en met tag Scala.

Het sorteren:

ASC- en DESC-sorteerparameters kunnen in URL worden doorgegeven, zoals:

GET / gebruikers / 123 / berichten? Sort = -updated_at

Retourneert berichten gesorteerd in aflopende volgorde van tijd van update datum.

9. HATEOAS

Hypermedia als Transfer Engine of Application State is een beperking van de REST-applicatiearchitectuur die deze onderscheidt van andere netwerkapplicatiearchitecturen.

Het biedt gemakkelijke navigatie door een bron en de beschikbare acties. Op deze manier hoeft een client niet te weten hoe hij met een applicatie moet werken voor verschillende acties, omdat alle metagegevens worden ingesloten in reacties van de server.

Laten we, om het beter te begrijpen, kijken naar de onderstaande reactie van gebruiker met ID 123 ophalen van de server:

{
"Name": "John Doe",
"Links": [
{
"Rel": "zelf",
"Href": "http: // localhost: 8080 / gebruikers / 123"
},
{
"Rel": "berichten",
"Href": "http: // localhost: 8080 / gebruikers / 123 / posts"
},
{
"Rel": "adres",
"Href": "http: // localhost: 8080 / gebruikers / 123 / adres"
}
]
}

Soms is het gemakkelijker om de links-indeling over te slaan en links op te geven als velden van een resource zoals hieronder:

{
"Name": "John Doe",
"Self": "http: // localhost: 8080 / gebruikers / 123",
"Posts": "http: // localhost: 8080 / gebruikers / 123",
"Adres": "http: // localhost: 8080 / gebruikers / 123 / adres"
}

Het is geen conventie die u elke keer moet volgen, omdat het afhankelijk is van resourcevelden / -grootte en acties die op resource kunnen worden uitgevoerd. Als bronnen verschillende velden bevatten die de gebruiker misschien niet wil doorlopen, is het een goed idee om navigatie naar subbronnen te tonen en HATEOAS te implementeren.

10. Staatloze authenticatie en autorisatie

REST API's moeten stateless zijn. Elk verzoek moet zelfvoorzienend zijn en moet worden vervuld zonder kennis van het voorafgaande verzoek. Dit gebeurt in het geval van het autoriseren van een gebruikersactie.

Eerder hebben ontwikkelaars gebruikersinformatie opgeslagen in server-side sessies, wat geen schaalbare benadering is. Daarom moet elk verzoek alle informatie van een gebruiker bevatten (als het een beveiligde API is), in plaats van te vertrouwen op eerdere verzoeken.

Dit beperkt API's niet tot een gebruiker als geautoriseerd persoon, omdat het ook autorisatie voor service mogelijk maakt. Voor gebruikersautorisatie biedt JWT (JSON Web Token) met OAuth2 een manier om dit te bereiken. Probeer bovendien voor service-to-service-communicatie de gecodeerde API-sleutel in de header door te geven.

11. Swagger voor documentatie

Swagger is een veelgebruikte tool voor het documenteren van REST API's die een manier biedt om het gebruik van een specifieke API te verkennen, waardoor ontwikkelaars het onderliggende semantische gedrag kunnen begrijpen. Het is een declaratieve manier om documentatie toe te voegen met behulp van annotaties die verder een JSON genereert die API's en hun gebruik beschrijft.

We hebben een Maven Archetype gemaakt waarmee je hier aan de slag kunt: Maven Archetype.

12. HTTP-statuscodes

Gebruik HTTP-statuscodes om het antwoord op een client te geven. Het kan een succes- of faalreactie zijn, maar het moet definiëren wat het respectieve succes of falen betekent vanuit een serverperspectief.

Hieronder staan ​​de categorieën antwoorden op basis van hun statuscodes:

2xx succes

200 OK: geretourneerd door een succesvolle GET- of DELETE-bewerking. PUT of POST kan hier ook gebruik van maken als de service na het maken of wijzigen geen bron terug wil sturen naar de client.

201 Gemaakt: reactie voor een succesvolle resourcecreatie door een POST-aanvraag.

3xx omleiding

304 Niet gewijzigd: gebruikt als de HTTP-cachingkop is geïmplementeerd.

4xx clientfouten

400 Bad Request: wanneer een HTTP-request body niet kan worden ontleed. Als een API bijvoorbeeld een body in een JSON-indeling verwacht voor een POST-aanvraag, maar de body van de aanvraag onjuist is opgemaakt.

401 Niet geautoriseerd: verificatie is mislukt (of er zijn geen referenties verstrekt) bij toegang tot de API.

403 Verboden: als een gebruiker niet geautoriseerd is om een ​​actie uit te voeren, hoewel de authenticatie-informatie correct is.

404 niet gevonden: als de gevraagde bron niet beschikbaar is op de server.

405 Methode niet toegestaan: als de gebruiker probeert een API-contract te overtreden, bijvoorbeeld een bron probeert bij te werken met behulp van een POST-methode.

5xx serverfouten

Deze fouten treden op als gevolg van serverstoringen of problemen met de onderliggende infrastructuur.

Afsluiten

Ontwikkelaars moeten wat tijd besteden aan het ontwerpen van REST API's, omdat de API een service zeer gebruiksvriendelijk of uiterst complex kan maken. Bovendien kan de volwassenheid van de API's eenvoudig worden gedocumenteerd met behulp van het Richardson Maturity Model.

Als u uw mening over de integratie met REST-services wilt delen en meer wilt weten over waar ik dagelijks mee bezig ben met Tempus of een demonstratie wilt plannen, neem dan contact met mij op via jay.kapadnis@hashmapinc.com.

Deel gerust via andere kanalen en blijf op de hoogte van alle nieuwe inhoud van Hashmap op https://medium.com/hashmapinc.

Jay Kapadnis is Tempus-architect bij Hashmap en werkt in het engineeringteam in verschillende sectoren met een groep innovatieve technologen en domeinexperts die hoogwaardige bedrijfsresultaten voor onze klanten versnellen.