RESTful Services Del II: Begrænsninger og mål

RESTful Services Del II: Begrænsninger og mål

I del I af denne serie skrev jeg om HTTP og dens konstruktioner, som de gælder for webservicedesign.

HTTP er kun en lille del af, hvad der går med at skrive moderne webtjenester.

Dette indlæg handler om, hvordan du anvender disse konstruktioner til at skabe vedligeholdelige, robuste tjenester.

Definition af REST

REST står for VE præsentations S Tate T ransfer. Det er en arkitektonisk stil. Dette betyder, at REST ikke pålægger en formel standard for at afgøre, om en webservice er RESTful. Snarere har det et sæt brede begrænsninger, hver med et specifikt mål for øje.

Disse begrænsninger blev først introduceret af Roy Fielding, som var en af ​​medforfatterne af HTTP-specifikationen tilbage i 2000.

Fielding's begrænsninger

Fielding skabte disse begrænsninger med det ultimative mål at gøre applikationer hurtigere, mere pålidelige og lettere at skalere.

Som webservicedesigner skal din tjeneste forsøge at overholde disse begrænsninger så tæt som muligt for at høste deres fordele. Så lad os dykke ned i dem.

Begrænsning nr. 1: Klient-serverarkitektur

Den første begrænsning, som REST foreslår, er adskillelsen af ​​serveren fra dens klient. Du bør tilskynde til adskillelse af bekymringer mellem din server og klienter, hvor det er muligt. Dit mål skal være at maksimere arbejdsdelingen - og minimere overlapning - mellem de to.

Serveren eller bagenden er typisk ansvarlig for lagring af din applikations vedvarende data sammen med al den forretningslogik, der kræves for at interagere med den. Dette kan omfatte brugergodkendelse, godkendelse, datavalidering osv.

Klienten eller frontend er ansvarlig for at stille anmodninger til tjenesten og derefter gøre noget meningsfuldt med det svar, den modtager.

Selve klienten kan være en webservice, i hvilket tilfælde den simpelthen bruger dataene. Alternativt kan det være brugervendt. Et eksempel på dette ville være en web- eller mobilapp. Her er det også ansvarligt for både at præsentere dataene for brugeren og præsentere en grænseflade, som brugeren kan interagere med .

Du skal være i stand til at behandle hver af disse to komponenter som en sort boks i forhold til hinanden. På denne måde kan de ændres uafhængigt. Dette tilskynder til modularitet i applikationen.

Dette koncept er ikke unikt for RESTFul-applikationer eller endda webapplikationer. De fleste udviklere prøver alligevel at opdele deres projekter i uafhængige komponenter. Men ved at angive dette som en eksplicit begrænsning af RESTful design, opfordrer Fielding yderligere denne praksis.

Endelig reducerer antallet af nødvendige logik ved at reducere antallet af ting, som serveren er ansvarlig for. Dette giver igen mulighed for bedre skalerbarhed og øget ydeevne.

Begrænsning nr. 2: Statsløshed

Den næste vigtige begrænsning, som REST foreslår, er statsløshed.

Generelt er hovedmålet med en statsløs tjeneste at gøre indgående anmodninger selvforsynende og udføre dem i fuldstændig isolation.

Hver anmodning skal have alle de oplysninger, som serveren muligvis har brug for for at behandle den korrekt og reagere. Med andre ord behøver serveren ikke at bruge oplysninger fra tidligere anmodninger. Ansvaret for at opretholde en klients applikationstilstand overdrages således til klienten selv.

For at forstå dette skal du overveje en meget enkel webservice, der er ansvarlig for at svare på en brugers søgeforespørgsler. Den nøjagtige repræsentation af den enhed, der søges efter, er irrelevant. Det vigtige er, at i stedet for at returnere hundredvis af søgeresultater på én gang, anvender serveren paginering : returnerer kun 10 resultater ad gangen ud af et vilkårligt stort resultatsæt.

I en traditionel “stateful” udviklingsmodel kan serveren være designet på en sådan måde, at den holder styr på alle sine klienter sammen med alle de sider, de allerede har åbnet.

Og så når en anmodning kommer ind på en ny side, er serveren i stand til at slå klienten op i sit system og bestemme den seneste side, den har modtaget.

Derefter kan serveren fortsætte med at svare med den næste side og opdatere sit system for at afspejle dette. Dette fortsætter, når klienten fortsætter med at navigere i resultatsættet.

I en alternativ, statsløs tilgang er ansvaret for at opretholde sin tilstand decentraliseret og flyttet til klienten. Klienten skal derefter specificere de faktiske sidetal for det ønskede resultat i modsætning til at bede om den næste side. For eksempel:

GET //my-awesome-web-service.com/pages/1GET //my-awesome-web-service.com/pages/3

En statsløs tilgang bringer et par store fordele med sig. Først og fremmest bliver det stadig mere beskatning at holde styr på klienttilstand på en server, når antallet af klienter skaleres.

For det andet og vigtigere er en statsløs tjeneste også let distribuerbar . Hvis en server er ansvarlig for at vedligeholde oplysninger om en applikations tilstand, er det også vigtigt, at fremtidige anmodninger dirigeres til den server, der lagrer disse oplysninger.

Hvis der er hundredvis af servere, der er ansvarlige for behandling af indgående anmodninger, skal der være en eller anden mekanisme på plads for at sikre, at anmodninger fra en bestemt klient altid ender på en bestemt serverinstans.

I tilfælde af at en serverinstans går ned, falder al information om en klients tilstand, der blev gemt på den server, sammen med den.

Selvfølgelig kan du komme med en arkitektur, hvor serverinstanser kan dele data indbyrdes. Men dette tilføjer en hel del kompleksitet.

En statsløs tjeneste derimod gør det meget nemmere at tilføje og fjerne serverforekomster på ad hoc-basis. Du kan derefter yderligere afbalancere belastningen mellem dem efter behov.

Da serverne er agnostiske for de indgående anmodninger, er opskalering bare et spørgsmål om at tilføje flere servere til belastningsbalanceren. På samme måde påvirker drab af servere - forsætligt eller på anden måde - ikke en tjenestes pålidelighed.

Selvfølgelig har denne enkelhed en pris. At have klienten vedlægge identiske data med hver anmodning er en potentiel kilde til redundans. Båndbredde er ikke gratis, så enhver overført yderligere information tilføjer noget overhead.

Begrænsning nr. 3: Cache

Den tredje begrænsning er eksplicit cacheabilitet. Ideen er at markere meddelelser, der returneres af en tjeneste, som eksplicit cacheable eller ikke cacheable. Hvis de kan caches, skal serveren finde ud af, hvor længe svaret er gyldigt.

Hvis klienten har adgang til et gyldigt cachelagret svar for en given anmodning, undgår den at gentage den samme anmodning. I stedet bruger den sin cachelagrede kopi. Dette hjælper med at lindre noget af serverens arbejde og bidrager således til skalerbarhed og ydeevne.

Dette er en form for optimistisk replikering - også kendt som doven replikering - hvor tjenesten ikke forsøger at garantere 100% konsistens mellem sig selv og dens klienter, medmindre det er absolut kritisk. I stedet bringer det dette offer i bytte for en gevinst i opfattet præstation.

For eksempel kan en API, der svarer til en blogplatform, vælge at gøre listen over blogindlæg cachelig i et par minutter, hvis den ved, at den hyppighed, som folk prøver at få adgang til indlæggene, langt overstiger den frekvens, hvormed nye indlæg oprettes. Som et resultat kan brugere lejlighedsvis blive præsenteret for uaktuelle data, men systemet som helhed klarer sig bedre.

Naturligvis er ressourceens cacheabilitet og dens varighed ikke universel og kræver en vis overvejelse. Hvis du valgte forkert, kan dette frustrere dine brugere.

Webtjenester opnår typisk cacherbarhed ved hjælp af standard Cache-Control- header. Nogle gange gør de dette sammen med andre overskrifter specificeret af HTTP.

Cache-Control-headeren fungerer effektivt som en switch, der bestemmer, om en browser skal cache det pågældende svar.

Ressourcer markeret som private cachelagres kun af klienten og er derfor kun begrænset til den ene klient.

Ressourcer, der er markeret som offentligt, kan på den anden side caches af en eller flere mellemliggende proxyer mellem tjenesten og klienten.

Som et resultat kan disse ressourcer muligvis serveres til flere brugere. Alternativt kan man videregive argumentet no-cache og helt stoppe enhver caching af ressourcen.

Sådan ser en af ​​disse Cache-Control-overskrifter ud:

Cache-Control: public;max-age=3431901

Overskriften giver dig også mulighed for at specificere, hvor lang tid ressourcen er gyldig. Dette lader klienten vide, hvornår den skal stoppe med at bruge sin cachelagrede kopi og anmode om en ny kopi.

Her er logikken bag dette:

Bortset fra dette har HTTP også mekanismer til at udføre det, der kaldes en betinget anmodning. Målet her er, at serveren kun returnerer bestemte ressourcer til klienten , når specifikke betingelser er opfyldt .

Forudsat at klienten har en gemt kopi af en ressource i sin cache, kan den anmode serveren om at afgøre, om der er en opdateret kopi af den samme ressource. Hvis der er en, returnerer serveren den nye kopi. Ellers beder det klienten om at fortsætte med at bruge sin lokale kopi.

Dette hjælper med at forhindre overflødig overførsel af data over netværket, samtidig med at det sikres, at klienten til enhver tid har adgang til nye data.

Der er et par måder, HTTP giver dig mulighed for at opnå dette:

Cachemetode nr. 1: Hvis-modificeret-siden / sidst-modificeret

Sammen med hvert svar, som serveren sender tilbage, kan den vælge at vedhæfte et sidst ændrede tidsstempel. Dette indikerer, hvornår ressourcen sidst blev ændret.

Når klienten har brug for at anmode om ressourcen igen i fremtiden, fremsætter den anmodningen til serveren som den normalt ville, men med et relevant If-Modified-Since- overskrift. Dette beder serveren om at returnere den nye kopi af ressourcen, hvis der findes en.

Ellers returnerer serveren statuskoden 304, sompålægger klienten at fortsætte med at bruge den kopi, den allerede har.

Caching-tilgang nr. 2: Hvis-ingen-match / ETag

Denne ordning fungerer svarende til den forrige, bortset fra den måde, ressourcer identificeres på. I stedet for at bruge tidsstempler sender serveren med hvert svar en unik hash, der forklarer ressourcens tilstand på det tidspunkt (kendt som ETag).

Ved fremtidige anmodninger sender klienten den relevante ETag til serveren. Hvis der findes en ressource med den samme ETag, beder serveren klienten om at fortsætte med at bruge den cachelagrede kopi. Ellers sender serveren en ny tilbage til klienten.

Cache er kompliceret. Når din tjeneste begynder at tilføje flere brugere, vil du gerne lære mere om caching og hvordan du kan bruge den til din fordel.

Begrænsning nr. 4: Ensartet grænseflade

Den Uniform interface (eller Uniform kontrakt ) fortæller enRESTful service, hvad der skal serveres i form af et dokument, et billede, et ikke-virtuelt objekt osv.

REST dikterer dog ikke, hvordan du vælger at interagere med disse ressourcer, så længe de er konsistente og godt forståede.

Generelt før en klient kan interagere med en RESTful-tjeneste, skal den aftale:

  1. Identifikation: Der skal være en måde til entydigt at identificere alle ressourcer, som tjenesten har at tilbyde.
  2. Manipulation: Der skal være et standardsæt af operationer, der kan udføres på en given ressource med forudsigelige resultater. Resultaterne af disse operationer skal også være selvbeskrivende og unikt forstået.

HTTP bruger f.eks. URL'er til identifikation af ressourcer. Det bruger også en håndfuld handlingsverb og veldokumenterede statuskoder for at lette interaktion med ressourcen. (For en mere detaljeret forklaring af HTTP's konstruktioner kan du gå tilbage og læse del I i denne serie.)

Indtil dette tidspunkt har vi betragtet RESTful-tjenester som strengt bundet til HTTP. Med hensyn til webtjenester er dette næsten altid nøjagtigt.

Men i teorien kan REST implementeres over enhver protokol, der giver en anstændig måde at opnå de to betingelser, jeg har beskrevet ovenfor. Af denne grund kaldes REST undertiden også REST over HTTP for at præcisere, at den bruges over internettet.

Begrænsning nr. 5: Et lagdelt system

Et lagdelt system bygger på den klientserver-begrænsning, vi diskuterede tidligere, og håndhæver en endnu mere adskillelse af bekymringer. Den overordnede arkitektur for din tjeneste kan opdeles i individuelle lag, der hver tjener en bestemt funktion.

Mere vigtigt er, at hvert lag skal handle uafhængigt og kun interagere med de lag, der umiddelbart støder op til det. Dette tvinger anmodninger om at forplante sig på en forudsigelig måde uden at omgå lag.

For eksempel for at skalere kan du bruge en proxy, der opfører sig som en belastningsafbalancering. Det eneste formål med proxyen ville derefter være at videresende indgående anmodninger til den relevante serverinstans.

Kunden behøver derimod ikke at være opmærksom på denne opdeling. Det fortsætter simpelthen med at anmode om den samme URL, uden bekymring med detaljerne i, hvordan anmodningerne behandles.

Tilsvarende kan der være et andet lag i arkitekturen, der er ansvarlig for caching af svar for at minimere det arbejde, der skal udføres af serveren.

Et andet lag kan opføre sig som en gateway og oversætte HTTP-anmodninger til andre protokoller.

En måde, du kunne bruge dette på, var at implementere en FTP-server. Klienten vil fortsætte med at stille anmodninger om, hvad den opfatter som en HTTP-server, mens du faktisk har en FTP-server, der udfører arbejdet under emhætten.

Ligesom sondringen mellem klient og server minimerer denne lagdelte systembegrænsning risikoen for koblingsfunktionalitet i din tjeneste, men på bekostning af ekstra omkostninger i systemet.

Konklusion

For at opsummere tingene har vi set på de vigtige begrænsninger, som du skal huske på, når du designer RESTful webtjenester. Jeg vil også understrege, at selvom dette er teknisk hårde krav, som en tjeneste skal opfylde for at blive betragtet som RESTful, sker det i praksis ikke altid.

Opbygning af reelle tjenester handler mere om at løse de aktuelle problemer end at imødekomme tekniske definitioner. Som et resultat bruges disse begrænsninger oftest som retningslinjer af udviklere og arkitekter, der derefter beslutter, hvilke regler der skal følges i deres bestræbelser på at nå deres egne specifikke mål.

Det er her udtrykkene delvist afslappende og fuldstændig afslappende kommer fra. Og faktisk,de fleste tjenester, du støder på online, er ikke teknisk fuldstændig RESTfulde.

I den næste og sidste del af denne serie vil jeg diskutere HATEOAS-principper såvel som Richardson Maturity Model. Dette giver en lidt mere kvantitativ tilgang til at bestemme, hvor RESTful en webtjeneste virkelig er. Find det her!

Jeg håber, dette var en nyttig introduktion til, hvad der går i at opbygge en RESTful applikation. At forstå REST-principperne vil helt sikkert hjælpe dig, når du arbejder med mange tredjeparts-API'er. Eller endda når du bygger dine egne applikationer på internettet, mobil eller andre steder.

Som en bonus har jeg også uploadet en præsentation, der er relevant for dette emne her. Slide-dækket er lånt fra en kort tale, jeg holdt for et par måneder siden på mit universitet med titlen "The Impact of a RESTful Architecture on Application Performance and Scalability." Jeg håber du finder det nyttigt :)

Lad mig vide i kommentarerne, hvis du har feedback eller er velkommen til at kontakte mig via min LinkedIn.

Her er nogle ressourcer til yderligere læsning om REST:

Nøgleprincipper for softwarearkitektur - MSDN

Hvil forklaret, en præsentation

Restful Web Services - Sam Ruby

WhatIsRest.com

Hvil i praksis