REST API Ontwikkelingstips en best practices - Deel 1

Introductie en planning

Dit is de eerste in een reeks van drie berichten op REST API's.

• Deel 1: Inleiding en planning
• Deel 2: Schemasuggesties, veelgemaakte fouten en afschrijvingen
• Deel 3: Documentatietips en verder gaan dan de basis

INVOERING

REST API's zijn tegenwoordig overal. Als u netwerk-compatibele toepassingen ontwikkelt, is de kans groot dat u ten minste één in uw code heeft verbruikt, en waarschijnlijk leest u dit omdat u op het punt staat er zelf een te schrijven.

Wat deze serie is en wat het niet is

Deze reeks berichten is geen inleiding tot REST. Het gaat ervan uit dat u een duidelijk begrip hebt van wat REST is en wat het beoogt te bereiken. Het is ook geenszins een uitgebreid artikel met Best Practices over het ontwerpen en ontwikkelen van web-API's. Er zijn er veel die al online beschikbaar zijn en ik zou willen voorstellen dat je er zoveel leest als je kunt.

Wat het meestal is, is een lijst met veel voorkomende en vaak vergeten fouten die mensen maken bij het ontwerpen en implementeren van REST API's. Ik weet het, niet alleen omdat ik ze ben tegengekomen in de API's van anderen, maar omdat ik er zelf een paar heb gemaakt. :)

Waarom dit werd geschreven

In een perfecte wereld is het eerste dat iemand direct na het ontwikkelen van een REST API moet doen, er een clienttoepassing voor schrijven. Ik heb het niet over een gebruikersinterface met een lijst met eindpunten die mensen kunnen bellen, in plaats van een concreet gebruik van uw API. Er is niets meer openend om de inefficiënties van uw creatie te onthullen, dan het zelf correct te gebruiken. Ik weet dit, omdat ik het tientallen keren moest doen.

Onze wereld is natuurlijk niet perfect, en meestal moet een back-endontwikkelaar overgaan op andere dingen nadat ze klaar zijn met de API-implementatie, maar alleen totdat de API-consumenten hem moeten oproepen om boete te doen voor zijn zonden. Ik heb ook vaak in die ongelukkige positie gezeten, dus hopelijk helpen mijn fouten en tips je om tijd te besparen - zodat je niet terug hoeft te keren naar je API-code totdat het tijd is om nieuwe functies toe te voegen.

PLANNING

Afbeelding vriendelijk verstrekt door Dan Bickell

1. Voordat u begint

Bestudeer zoveel REST API-ontwerp- en ontwikkelingsdocumenten en boeken als u kunt vinden! Ik zal hier geen algemene tips noemen, zoals het gebruik van een zelfstandig naamwoord in plaats van een werkwoord-URI (oeps, ik heb het net gedaan ...) enz., Maar dat is omdat ik veronderstel dat je er al ergens anders over hebt gelezen.

Overweeg alternatieven

REST is behoorlijk populair als paradigma, maar het komt in veel smaken. Voordat u verder gaat, moet u er zo veel mogelijk bekijken. Vergeet niet om GraphQL te controleren, een geheel andere aanpak, die niet alleen geweldig lijkt voor bepaalde gebruiksscenario's, maar ook wordt gebruikt door Facebook (die het heeft ontwikkeld) en de nieuwe v4 API van GitHub.

Zie wat anderen hebben gedaan

Bekijk en probeer zoveel mogelijk populaire API's van gerenommeerde organisaties te gebruiken. Hier zijn een paar om mee te beginnen: GitHub, Stripe, Twitter, PayPal

2. De stichting

Ga er niet vanuit dat uw API klein zal blijven - het gebeurt bijna nooit. Zelfs als je de enige bent die het voor je eigen client-app gebruikt, heb je al snel een extra eindpunt, paginering, analyse, een testmodus nodig en wie weet wat nog meer, en dat is nog voordat je app populair wordt en andere mensen beginnen toegang vragen tot uw API…

OK - misschien is dat een stuk; maar zoals het meestal gebeurt bij de ontwikkeling van software, betaalt u er op de lange termijn duur voor als u niet vroeg een solide basis legt. Omdat API's consistent moeten zijn om gemakkelijk te kunnen worden verbruikt, zal het proberen om functies toe te voegen met duct-tape het niet alleen moeilijker maken voor u, maar ook voor uw klanten.

Bovendien, hoe beter je dingen schoon houdt, hoe minder tijd het kost om ze te voltooien en vrij snel ...

3. Specificatie

Praten over een sterke basis; probeer de specificatie voor uw API te maken voordat u daadwerkelijk code begint te schrijven. Ik weet dat het saai klinkt als je het nog niet eerder hebt gedaan, maar het loont op de lange termijn en bespaart je veel tijd en gedoe.

OpenAPI-specificatie (OAS - voorheen Swagger) lijkt op dit moment de meest populaire manier om te gaan, omdat steeds meer organisaties en alternatieven hier samenkomen. Als alternatief is Postman een geweldige API-ontwikkelomgeving, maar het is alleen gratis voor individuen of kleine teams van ontwikkelaars.

Ik zou sterk aanbevelen om deze tip niet te negeren, tenzij je een kleine interne API ontwikkelt die alleen jij zult consumeren.

4. Versiebeheer

Ik zal me in dit bericht niet concentreren op verschillende versiemethoden, omdat er online veel specifieke bronnen over dit onderwerp zijn. Ik zal alleen proberen te benadrukken hoe belangrijk het is dat je een robuuste versiebenadering kiest en deze religieus volgt. Ik zal ook een aanpak presenteren die me door de jaren heen goed heeft gediend.

Waarom het belangrijk is

Een krachtige versiebenadering biedt gemoedsrust aan uw consumenten (en dus uw eindgebruikers) omdat het voorkomt dat API-wijzigingen de functionaliteit van bestaande client-applicaties verstoren. Zelfs wanneer clienttoepassingen zelf worden ontwikkeld door dezelfde ontwikkelaar of dezelfde organisatie als de API, zijn er veel scenario's waarin verouderde clients mogelijk nog in gebruik zijn op het moment dat een API-update beschikbaar is.

Een veel voorkomend verschijnsel van dit fenomeen zijn mobiele of desktop OS-clienttoepassingen, waarbij de ontwikkelaars zelden de volledige controle hebben over de updatecyclus. Hoe goed en geautomatiseerd uw client-updatemechanismen ook zijn, u kunt bijna nooit 100% zeker zijn dat uw gebruikers de nieuwste versie van uw client-apps gebruiken.

iOS heeft een zeer betrouwbaar automatisch updatemechanisme voor applicaties die standaard zijn ingeschakeld, maar afhankelijk van de voorkeuren en netwerkstatus van een gebruiker, heeft hun apparaat mogelijk geen kans gehad om uw client-app bij te werken de volgende keer dat het wordt uitgevoerd. Hetzelfde geldt voor nieuwere versies van Android, terwijl oudere versies zelfs nog ver achterblijven bij app-updates.

Aan de andere kant bieden desktop-apps al dan niet een automatisch updatemechanisme, maar meestal kiezen ze voor opt-in en er zijn altijd gevallen (zoals bedrijfsomgevingen) die geen onmiddellijke updates toestaan. Zelfs browser-client-apps kunnen (en moeten in de meeste gevallen) worden losgekoppeld van hun backend en hebben daarom een ​​geheel andere releasecyclus dan de API.

Communiceer wijzigingen aan uw consumenten

Zelfs als u de perfecte API hebt met het beste versiesysteem, betekent dit niets als uw consumenten niet op de hoogte zijn van het volledige potentieel. Het communiceren van veranderingen en nieuwe functies is cruciaal voor uw gebruikers om er volledig van te kunnen profiteren. Nog belangrijker is om uw gebruikers vroeg genoeg te waarschuwen voor aspecten die worden afgeschaft of verwijderd, zodat ze voldoende tijd hebben om nieuwe versies van hun klanten bij te werken, te testen en te verzenden.

Het bijhouden van een actuele documentatie en het vrijgeven van gedetailleerde changelogs voor elke versie is van het grootste belang en zou onderdeel moeten zijn van uw ontwikkelingscyclus.

Major / minor versie aanpak

Een versiebenadering die ik door de jaren heen erg op prijs ben gaan stellen, is een groot / klein versieschema. Uw API wordt gekenmerkt door een hoofdversienummer, dat (als u het goed doet) alleen wordt bijgewerkt als er wijzigingen zijn verbroken, en een ondergeschikt versienummer, dat telkens wordt bijgewerkt als er kleine incrementele toevoegingen zijn.

Vanuit een andere invalshoek bekeken, garandeert elke belangrijke versie dat de structuur van de API-bronnen en het schema niet zullen worden afgebroken voor de duur van zijn levenscyclus, ongeacht hoeveel kleinere versies er ondertussen worden vrijgegeven. Kleine versies zijn achterwaarts compatibel.

Het is gebruikelijk dat de hoofdversie deel uitmaakt van de basis-URL van de API (bijvoorbeeld https://api.myserver.com/v1/endpoint) en dat de secundaire versie via een verzoekkop kan worden geselecteerd. Als de koptekst van het verzoek niet is opgegeven, wordt de nieuwste secundaire versie gebruikt. Er zijn veel populaire API's die deze aanpak volgen, mijn favoriete is Stripe (die releasedata gebruikt voor secundaire versies).

Hoewel ik deze aanpak in de volgende secties opnieuw zal bespreken wanneer je over updates voor je API spreekt, is het aan jou om je eigen formele versiebeheersysteem te kiezen dat het beste werkt voor jouw vereisten. Onthoud dat als je dat doet, je je eraan zult moeten binden.

5. Testen

Dit is prima als je niet in productie bent

Als een integraal onderdeel van het softwareontwikkelingsproces in het algemeen, is testen essentieel voor uw API. Aangezien API's meestal dienen als de link tussen de single-source-of-truth die de server is en een of meer client-applicaties, moeten ze onder alle omstandigheden betrouwbaar zijn en het zich niet veroorloven om op een of andere manier in productie te gaan. Omdat ze meestal worden blootgesteld aan internet en dus kwetsbaar zijn voor een groot aantal risico's, moeten ze bovendien grondig worden getest op een groot aantal veel voorkomende en niet zo veel voorkomende scenario's.

Handmatig testen door uw eindpunten te bellen via tools zoals Swagger, Postman of REST-console, kan u alleen helpen tijdens de eerste babystappen van ontwikkeling, wanneer u nog steeds de verschillende basisfuncties test. Het vanaf het begin onderhouden van een reeks geautomatiseerde tests maakt een wereld van verschil voor de kwaliteit van het eindproduct.

Vanwege hun aard zijn API's ideale kandidaten voor functionele testen. Unit testen van hun interne implementatie is erg belangrijk (zoals voor elk ander stuk software), maar naar mijn mening biedt functioneel testen van een API en het vergelijken met een black box veel meer waarde voor de tijd die u eraan besteedt.

Het onderhouden van een testdatabase die u tijdens het testen kunt instellen en afbreken, is een essentieel onderdeel van het proces. Blijf gegevens toevoegen die hebben bijgedragen aan problemen in het verleden (waargenomen tijdens de ontwikkeling of gerapporteerd door uw consumenten) en verrijk uw testpakket met regressietests om ervoor te zorgen dat u voor eens en voor altijd van die bugs af bent.

Ga er nooit van uit dat uw validatie van invoerparameters voltooid is totdat u zelfs de vreemdste randgevallen hebt getest (vergeet niet dat uw client-apps zelf behoorlijk buggy kunnen zijn). Investeer ten slotte tijd in een goede loginfrastructuur om die paar resterende runtime-bugs op te vangen, het consumentengedrag te observeren en die informatie te gebruiken om nog meer testscenario's te creëren.

6. Implementatie

Zoals je misschien al hebt opgemerkt (of zal merken als je blijft lezen), richt dit bericht zich sterk op het maken van een API die dingen niet kapot maakt. De meest angstaanjagende fase om dingen in bijna alle softwareproducten te breken, is natuurlijk de implementatie.

In de meeste gevallen zijn de kansen op een probleem tijdens de implementatie zeer klein als u correct hebt getest en versiebeheer; hier zijn echter een paar tips die u misschien extra kunnen helpen.

Ontkoppel alles

Hier is een veel voorkomend scenario:

Uw API levert gegevens aan een aantal B2B-clients die zijn ontwikkeld door externe organisaties, bedient een aantal mobiele apps en een web-app die is ontwikkeld door uw eigen organisatie en is een integraal onderdeel van een servertoepassing - die toevallig ook toegankelijk is via internet , voor administratiedoeleinden.

Dat klinkt misschien ingewikkeld, maar ik heb het in het verleden al vaak gezien in eenvoudiger of complexere variaties. Het belangrijkste punt is dat de API, hoewel het de hoeksteen van een organisatie is, vaak nauw is gekoppeld aan ten minste één server-app die andere verantwoordelijkheden heeft.

Dat betekent dat wanneer het tijd is om de server-app bij te werken, als er iets kapot gaat, de kans groot is dat de API ook kapot gaat. Als dat gebeurt, zal de API al zijn consumenten meesleuren en uiteindelijk zal de toorn van de eindgebruikers op het bedrijf neerdalen.

Uw gebruikers lastigvallen is het laatste wat u wilt

Een ander tekort aan strakke koppeling in deze context is dat de releasecyclus van de ene app van invloed is op alle andere. Dat vereist een complexe planning en orkestratie van implementaties. Bovendien heeft het vanuit zakelijk oogpunt geen zin (elke app moet op zijn eigen tijd worden uitgegeven - zonder de rest te beïnvloeden).

Als uw API en de rest van uw apps worden ontwikkeld als onafhankelijke modules van uw infrastructuur, verdwijnt dit allemaal. Iemand zou kunnen beweren dat het hebben van meer afzonderlijke modules meer faalpunten betekent, maar dat kan worden opgelost met de juiste versies en testen. Bovendien, zelfs als de nieuwe versie van uw API breekt bij de implementatie, zal uw team de eerste zijn die het weet. In dit geval, als er niets beters kan worden gedaan, kunt u de releases van uw klanten altijd een paar dagen uitstellen totdat u zeker weet dat alles goed werkt.

Een gevaarlijk geval dat u moet beschermen met rigoureuze testen, is wanneer de nieuwe versie van uw server-app de bestaande versie van uw API breekt. Nogmaals, de enige manier om dit te voorkomen is (natuurlijk) door middel van een strikt ontwikkelingsproces met de juiste versies en testen. Het behandelen van alle delen van uw infrastructuur als afzonderlijke modules moedigt die aanpak nog verder aan.

7. (Sierlijke) afschrijving

Op een gegeven moment, naarmate uw app volwassen wordt, is het onvermijdelijk dat u uw huidige hoofdversie van de API moet vervangen door een nieuwe. Client-apps die nog in ontwikkeling zijn, moeten ook upgraden naar de nieuwe versie, maar dat kan enige tijd duren.

Bovendien zijn er gevallen waarin zelfs onmiddellijke actie van de ontwikkelaars niet betekent dat de clienttoepassingen onmiddellijk moeten worden bijgewerkt. Hoewel bijgewerkte versies van web-apps beschikbaar kunnen worden gemaakt voor de eindgebruikers zodra ze worden uitgebracht, blijven oudere versies van mobiele en native OS-apps vaak lang bestaan. Sommige gebruikers begrijpen het updateproces van apps op hun telefoon of computer niet echt (of zijn zich er zelfs niet van bewust). Als die apps plotseling niet meer werken, kan de reactie van de gebruiker zijn om gewoon te stoppen met het gebruik ervan.

Afschrijving van een belangrijke API-versie betekent niet dat de service wordt onderbroken. De verouderde versie zou precies zo moeten blijven werken als hij deed, voor een periode (zo lang mogelijk) die duidelijk en herhaaldelijk (naarmate het einde nadert) aan uw consumenten zal worden gecommuniceerd. Idealiter zouden oudere versies van uw API nooit moeten stoppen met werken, tenzij ze een beveiligingsrisico vormen of anderszins schade toebrengen aan uw backend.

8. Vaak genegeerde goede praktijken

U kunt meervouds- of enkelvoudsvormen gebruiken voor bronnen, maar niet beide

/ cars is prima en dat geldt ook voor / car, maar je kunt ze niet allebei gebruiken. Kies een formulier en houd u eraan in uw API. Als u dat niet doet, zult u uw consumenten en misschien zelfs uw eigen ontwikkelaars of uzelf in de toekomst verwarren.

Retourneer bijgewerkte objecten in PUT- en PATCH-antwoorden

Na een succesvol verzoek via PUT- of PATCH-werkwoorden, moet de client meestal de status van de bijgewerkte bron weten. Omdat het heel goed mogelijk is dat meerdere clients deze tegelijkertijd bijwerken, is dit de enige manier om iedereen op de hoogte te houden van de status van de bron op het moment dat de update plaatsvond.

Cookies en PHPSESSIONID

Deze is heel gebruikelijk in door PHP ontwikkelde applicaties. De API gebruikt zijn eigen aangepaste authenticatietoken, maar zonder medeweten van de ontwikkelaar die PHP's standaard sessie-afhandeling gebruikt, bevatten alle antwoorden ook de gevreesde PHPSESSIONID-cookie! Dit veroorzaakt op de lange termijn allerlei soorten bugs, omdat niemand (inclusief de ontwikkelaar) op de hoogte is van de cookie, omdat niemand denkt dat ze deze daar plaatsen.

Cookies zijn in het algemeen niet expliciet verboden door REST. Ze kunnen problemen veroorzaken als ze onjuist worden gebruikt (bijvoorbeeld als u probeert toegang te krijgen tot een afzonderlijk domein dat ook via uw API-mechanisme moet worden geautoriseerd), maar ze zijn niet verboden door een specificatie. Wat echter moet worden vermeden, is het gebruik van meer dan één vorm van authenticatie tegelijkertijd.

Wat betreft de sessiebehandeling van PHP, moet u nooit vertrouwen op de standaard PHP-cookiebenadering voor uw API, tenzij u wilt dat de PHPSESSIONID-cookie fungeert als het authenticatietoken van uw API (die ik op geen enkele manier aanbeveel!). Mijn advies zou zijn om een ​​aangepast sessiebehandelingsmechanisme te implementeren dat de door u gewenste authenticatiemethode implementeert.

Stel interne fouten of implementatiedetails niet bloot

In de loop der jaren heb ik dit in talloze gelegenheden gezien, zelfs in populaire API's van grote bedrijven. Het is niet cool om interne (zoals SQL) fouten in je antwoorden bloot te leggen! Zoek een betrouwbare manier om deze te loggen voor toekomstig gebruik, maar vertaal ze naar een generieke 500 - Interne serverfout in uw API-antwoorden.

De verplichte xkcd - altijd relevant.

Dit is een van de eerste dingen die je vroeg in het ontwikkelingsproces moet doen. Beveiliging moet van het grootste belang zijn voor een service die op internet wordt aangeboden.

Dit was de eerste in een reeks van drie berichten op REST API's.

Je kunt de volgende hier lezen:
Deel 2: Schemasuggesties, veelgemaakte fouten en afschrijving