Dela via


Metodtips för RESTful-webb-API-design

En RESTful-webb-API-implementering är ett webb-API som använder rest-arkitekturprinciper (Representational State Transfer) för att uppnå ett tillståndslöst, löst kopplat gränssnitt mellan en klient och tjänst. Ett webb-API som är RESTful stöder HTTP-standardprotokollet för att utföra åtgärder på resurser och returnera representationer av resurser som innehåller hypermedialänkar och HTTP-åtgärdsstatuskoder.

Ett RESTful-webb-API bör överensstämma med följande principer:

  • Plattformsoberoende, vilket innebär att klienter kan anropa webb-API:et oavsett den interna implementeringen. För att uppnå plattformsoberoende använder webb-API:et HTTP som ett standardprotokoll, tillhandahåller tydlig dokumentation och stöder ett välbekant datautbytesformat som JSON eller XML.

  • Lös koppling, vilket innebär att klienten och webbtjänsten kan utvecklas oberoende av varandra. Klienten behöver inte känna till den interna implementeringen av webbtjänsten och webbtjänsten behöver inte känna till den interna implementeringen av klienten. För att uppnå lös koppling i ett RESTful-webb-API använder du endast standardprotokoll och implementerar en mekanism som gör att klienten och webbtjänsten kan komma överens om formatet för data som ska utbytas.

I den här artikeln beskrivs metodtips för att utforma RESTful-webb-API:er. Den omfattar även vanliga designmönster och överväganden för att skapa webb-API:er som är lätta att förstå, flexibla och underhållsbara.

Designbegrepp för RESTful-webb-API

För att implementera ett RESTful-webb-API måste du förstå följande begrepp.

  • URI (Uniform Resource Identifier): REST-API:er är utformade kring resurser, som är alla typer av objekt, data eller tjänster som klienten kan komma åt. Varje resurs representeras av en URI som unikt identifierar resursen. URI:n för en viss kundbeställning kan till exempel vara:

    https://api.contoso.com/orders/1
    
  • Resursrepresentation definierar hur en resurs som identifieras av dess URI kodas och transporteras via HTTP-protokollet i ett specifikt format, till exempel XML eller JSON. Klienter som vill hämta en specifik resurs måste använda resursens URI i begäran till API:et. API:et returnerar en resursrepresentation av de data som URI:n anger. En klient kan till exempel göra en GET-begäran till URI-identifieraren https://api.contoso.com/orders/1 för att ta emot följande JSON-brödtext:

    {"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}
    
  • Enhetligt gränssnitt är hur RESTful-API:er uppnår lös koppling mellan klient- och tjänstimplementeringar. För REST-API:er som bygger på HTTP omfattar det enhetliga gränssnittet att använda http-standardverb för att utföra åtgärder som GET, POST, PUT, PATCHoch DELETE på resurser.

  • Tillståndslös begärandemodell: RESTful-API:er använder en tillståndslös begärandemodell, vilket innebär att HTTP-begäranden är oberoende och kan inträffa i valfri ordning. Därför är det inte möjligt att behålla tillfällig tillståndsinformation mellan begäranden. Den enda plats där information lagras finns i själva resurserna, och varje begäran bör vara en atomisk åtgärd. En tillståndslös begäransmodell stöder hög skalbarhet eftersom den inte behöver upprätthålla någon koppling mellan klienter och specifika servrar. Den tillståndslösa modellen kan dock också begränsa skalbarheten på grund av utmaningar med skalbarheten för webbtjänstens backend-lagring. Mer information om strategier för att skala ut ett datalager finns i Datapartitionering.

  • Hypermedia-länkar: REST-API:er kan drivas av hypermedialänkar som finns i varje resursrepresentation. Följande kodblock visar till exempel en JSON-representation av en order. Den innehåller länkar för att hämta eller uppdatera kunden som är associerad med ordern.

    {
      "orderID":3,
      "productID":2,
      "quantity":4,
      "orderValue":16.60,
      "links": [
        {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"GET" },
        {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"PUT" }
      ]
    }
    

Definiera RESURS-URI:er för RESTful-webb-API:er

Ett RESTful-webb-API är organiserat kring resurser. Om du vill organisera API-designen kring resurser definierar du resurs-URI:er som mappar till affärsentiteterna. När det är möjligt kan du basera resurs-URI:er på substantiv (resursen) och inte verb (åtgärderna på resursen).

I ett e-handelssystem kan till exempel de primära affärsentiteterna vara kunder och beställningar. För att skapa en order skickar en klient orderinformationen i en HTTP POST-begäran till resurs-URI:n. HTTP-svaret på begäran anger om beställningen har skapats.

URI:n för att skapa orderresursen kan vara ungefär så här:

https://api.contoso.com/orders // Good

Undvik att använda verb i URI:er för att representera åtgärder. Följande URI rekommenderas till exempel inte:

https://api.contoso.com/create-order // Avoid

Entiteter grupperas ofta tillsammans i samlingar som kunder eller beställningar. En samling är en separat resurs från objekten i samlingen, så den bör ha en egen URI. Följande URI kan till exempel representera samlingen med beställningar:

https://api.contoso.com/orders

När klienten har hämtat samlingen kan den göra en GET-begäran till URI:n för varje objekt. Om du till exempel vill ta emot information om en specifik order utför klienten en HTTP GET-begäran på URI https://api.contoso.com/orders/1 :n för att ta emot följande JSON-brödtext som en resursrepresentation av interna orderdata:

{"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}

Namngivningskonventioner för resurs-URI

När du utformar ett RESTful-webb-API är det viktigt att du använder rätt namngivnings- och relationskonventioner för resurser:

  • Använd substantiv för resursnamn. Använd substantiv för att representera resurser. Använd till exempel /orders i stället för /create-order. Metoderna HTTP GET, POST, PUT, PATCH och DELETE innebär redan den verbala åtgärden.

  • Använd plurala substantiv för att namnge samlings-URI:er. I allmänhet hjälper det till att använda plurala substantiv för URI:er som refererar till samlingar. Det är en bra idé att organisera URI:er för samlingar och objekt i en hierarki. Till exempel /customers är sökvägen till kundens samling och /customers/5 är sökvägen till kunden med ett ID som är lika med 5. Den här metoden hjälper till att hålla webb-API:et intuitivt. Dessutom kan många webb-API-ramverk dirigera begäranden baserat på parametriserade URI-sökvägar, så att du kan definiera en väg för sökvägen /customers/{id}.

  • Tänk på relationerna mellan olika typer av resurser och hur du kan exponera dessa associationer. Kan /customers/5/orders till exempel representera alla beställningar för kund 5. Du kan också närma dig relationen i den andra riktningen genom att representera associationen från en beställning till en kund. I det här scenariot kan URI:n vara /orders/99/customer. Att utöka den här modellen för långt kan dock bli besvärligt att implementera. En bättre metod är att inkludera länkar i brödtexten i HTTP-svarsmeddelandet så att klienter enkelt kan komma åt relaterade resurser. Använd Hypertext som motor för applikationstilstånd (HATEOAS) för att möjliggöra navigering till relaterade resurser beskriver den här mekanismen mer detaljerat.

  • Håll relationerna enkla och flexibla. I mer komplexa system kan du vara benägen att tillhandahålla URI:er som gör att klienten kan navigera i flera nivåer av relationer, till exempel /customers/1/orders/99/products. Den här komplexitetsnivån kan dock vara svår att underhålla och är oflexibel om relationerna mellan resurserna ändras i framtiden. Försök i stället att hålla URI:er relativt enkla. När ett program har en referens till en resurs bör du kunna använda den här referensen för att hitta objekt som är relaterade till den resursen. Du kan ersätta föregående fråga med URI /customers/1/orders :n för att hitta alla beställningar för kund 1 och sedan använda /orders/99/products för att hitta produkterna i den här ordningen.

    Tips/Råd

    Undvik att kräva resurs-URI:er som är mer komplexa än samling/objekt/samling.

  • Undvik ett stort antal små resurser. Alla webbbegäranden medför en belastning på webbservern. Ju fler begäranden, desto större belastning. Webb-API:er som exponerar ett stort antal små resurser kallas chattiga webb-API:er. Försök att undvika dessa API:er eftersom de kräver att ett klientprogram skickar flera begäranden för att hitta alla data som krävs. Överväg i stället att avnormalisera data och kombinera relaterad information till större resurser som kan hämtas via en enda begäran. Du behöver dock fortfarande balansera den här metoden mot kostnaden för att hämta data som klienten inte behöver. Stor objekthämtning kan öka svarstiden för en begäran och medföra mer bandbreddskostnader. Mer information om dessa prestandaskydd finns i Chatty I/O och Extraneous Fetching.

  • Undvik att skapa API:er som speglar den interna strukturen för en databas. Syftet med REST är att modellera affärsentiteter och de åtgärder som ett program kan utföra på dessa entiteter. En klient ska inte exponeras för den interna implementeringen. Om dina data till exempel lagras i en relationsdatabas behöver webb-API:et inte exponera varje tabell som en samling resurser. Den här metoden ökar attackytan och kan leda till dataläckage. Tänk i stället på webb-API:et som en abstraktion av databasen. Om det behövs introducerar du ett mappningslager mellan databasen och webb-API:et. Det här lagret säkerställer att klientprogram isoleras från ändringar i det underliggande databasschemat.

Tips/Råd

Det kanske inte går att mappa varje åtgärd som implementeras av ett webb-API till en specifik resurs. Du kan hantera dessa icke-resursscenarier via HTTP-begäranden som anropar en funktion och returnera resultatet som ett HTTP-svarsmeddelande.

Ett webb-API som implementerar enkla kalkylatoråtgärder som att lägga till och subtrahera kan till exempel tillhandahålla URI:er som exponerar dessa åtgärder som pseudoresurser och använder frågesträngen för att ange de obligatoriska parametrarna. En GET-begäran till URI /add?operand1=99&operand2=1 returnerar ett svarsmeddelande med brödtexten som innehåller värdet 100.

Du bör dock använda dessa former av URI:er sparsamt.

Definiera RESTful-webb-API-metoder

RESTful-webb-API-metoder överensstämmer med de begärandemetoder och medietyper som definieras av HTTP-protokollet. I det här avsnittet beskrivs de vanligaste metoderna för begäranden och de medietyper som används i RESTful-webb-API:er.

HTTP-begärandemetoder

HTTP-protokollet definierar många metoder för begäranden som anger vilken åtgärd du vill utföra på en resurs. De vanligaste metoderna som används i RESTful-webb-API:er är GET, POST, PUT, PATCH och DELETE. Varje metod motsvarar en specifik åtgärd. När du utformar ett RESTful-webb-API använder du dessa metoder på ett sätt som överensstämmer med protokolldefinitionen, resursen som används och den åtgärd som utförs.

Det är viktigt att komma ihåg att effekten av en specifik begärandemetod bör bero på om resursen är en samling eller ett enskilt objekt. Följande tabell innehåller några konventioner som de flesta RESTful-implementeringar använder.

Viktigt!

I följande tabell används en exempelentitet för e-handel customer . Ett webb-API behöver inte implementera alla begärandemetoder. De metoder som implementeras beror på det specifika scenariot.

Resurs POST STÄLLA TA BORT
/kunder Skapa en ny kund Hämta alla kunder Massuppdatering av kunder Ta bort alla kunder
/kunder/1 Fel Hämta information för kund 1 Uppdatera informationen för kund 1 om den finns Ta bort kund 1
/kunder/1/beställningar Skapa en ny order för kund 1 Hämta alla beställningar för kund 1 Massuppdatering av beställningar för kund 1 Ta bort alla beställningar för kund 1

GET-förfrågningar

En GET-begäran hämtar en representation av resursen vid den angivna URI:n. Brödtexten i svarsmeddelandet innehåller information om den begärda resursen.

En GET-begäran bör returnera någon av följande HTTP-statuskoder:

HTTP-statuskod Förnuft
200 (OK) Metoden har returnerat resursen.
204 (inget innehåll) Svarstexten innehåller inget innehåll, till exempel när en sökbegäran returnerar inga matchningar i HTTP-svaret.
404 (hittades inte) Det går inte att hitta den begärda resursen.

POST-begäranden

En POST-begäran bör skapa en resurs. Servern tilldelar en URI för den nya resursen och returnerar den URI:n till klienten.

Viktigt!

För POST-begäranden ska en klient inte försöka skapa en egen URI. Klienten bör skicka begäran till samlingens URI och servern ska tilldela en URI till den nya resursen. Om en klient försöker skapa en egen URI och utfärdar en POST-begäran till en specifik URI returnerar servern HTTP-statuskod 400 (BAD REQUEST) för att indikera att metoden inte stöds.

I en RESTful-modell används POST-begäranden för att lägga till en ny resurs i samlingen som URI:n identifierar. En POST-begäran kan dock också användas för att skicka data för bearbetning till en befintlig resurs, utan att skapa någon ny resurs.

En POST-begäran ska returnera någon av följande HTTP-statuskoder:

HTTP-statuskod Förnuft
200 (OK) Metoden har bearbetats men skapar ingen ny resurs. Resultatet av åtgärden kan ingå i svarstexten.
201 (Skapad) Resursen skapades framgångsrikt. URI:n för den nya resursen ingår i platsrubriken för svaret. Svarstexten innehåller en representation av resursen.
204 (inget innehåll) Svarstexten innehåller inget innehåll.
400 (felaktig begäran) Klienten har placerat ogiltiga data i begäran. Svarstexten kan innehålla mer information om felet eller en länk till en URI som innehåller mer information.
405 (metoden tillåts inte) Klienten har försökt göra en POST-begäran till en URI som inte stöder POST-begäranden.

PUT-begäran

En PUT-begäran bör uppdatera en befintlig resurs om den finns eller i vissa fall skapa en ny resurs om den inte finns. Så här gör du en PUT-begäran:

  1. Klienten anger URI:n för resursen och innehåller en begärandetext som innehåller en fullständig representation av resursen.
  2. Klienten gör begäran.
  3. Om det redan finns en resurs som har den här URI:n ersätts den. Annars skapas en ny resurs om vägen stöder den.

PUT-metoder tillämpas på resurser som är enskilda objekt, till exempel en specifik kund, i stället för samlingar. En server kan ha stöd för uppdateringar men inte skapa via PUT. Om du vill stödja skapande via PUT beror på om klienten på ett meningsfullt och tillförlitligt sätt kan tilldela en URI till en resurs innan den finns. Om det inte går kan du använda POST för att skapa resurser och låta servern tilldela URI:n. Använd sedan PUT eller PATCH för att uppdatera URI:n.

Viktigt!

PUT-begäranden måste vara idempotent, vilket innebär att om samma begäran skickas flera gånger resulterar det alltid i att samma resurs ändras med samma värden. Om en klient skickar en PUT-begäran igen bör resultatet förbli oförändrat. Post- och PATCH-begäranden är däremot inte garanterade att vara idempotenta.

En PUT-begäran bör returnera någon av följande HTTP-statuskoder:

HTTP-statuskod Förnuft
200 (OK) Resursen har uppdaterats.
201 (Skapad) Resursen skapades framgångsrikt. Svarstexten kan innehålla en representation av resursen.
204 (inget innehåll) Resursen har uppdaterats, men svarstexten innehåller inget innehåll.
409 (konflikt) Det gick inte att slutföra begäran på grund av en konflikt med resursens aktuella tillstånd.

Tips/Råd

Överväg att implementera HTTP PUT-massåtgärder som kan uppdatera flera resurser samtidigt i en samling. PUT-begäran ska ange samlingens URI. Begärandetexten bör ange information om de resurser som ska ändras. Den här metoden kan bidra till att minska chattigheten och förbättra prestandan.

PATCH-begäranden

En PATCH-begäran utför en partiell uppdatering av en befintlig resurs. Klienten anger URI:n för resursen. Begärandetexten anger en uppsättning ändringar som ska tillämpas på resursen. Den här metoden kan vara effektivare än att använda PUT-begäranden eftersom klienten bara skickar ändringarna och inte hela representationen av resursen. PATCH kan också skapa en ny resurs genom att ange en uppsättning uppdateringar till en tom resurs eller null-resurs om servern stöder den här åtgärden.

Med en PATCH-begäran skickar klienten en uppsättning uppdateringar till en befintlig resurs i form av ett korrigeringsdokument. Servern bearbetar korrigeringsdokumentet för att utföra uppdateringen. Korrigeringsdokumentet anger endast en uppsättning ändringar som ska tillämpas i stället för att beskriva hela resursen. Specifikationen för PATCH-metoden RFC 5789 definierar inte ett specifikt format för korrigeringsdokument. Formatet måste härledas från medietypen i begäran.

JSON är ett av de vanligaste dataformaten för webb-API:er. De två huvudsakliga JSON-baserade korrigeringsformaten är JSON-korrigering och JSON-kopplingskorrigering.

JSON-sammanslagningskorrigering är enklare än JSON-korrigering. Korrigeringsdokumentet har samma struktur som den ursprungliga JSON-resursen, men det innehåller bara den delmängd av fält som ska ändras eller läggas till. Dessutom kan ett fält tas bort genom att null ange fältvärdet i korrigeringsdokumentet. Den här specifikationen innebär att kopplingskorrigering inte är lämplig om den ursprungliga resursen kan ha explicita null-värden.

Anta till exempel att den ursprungliga resursen har följande JSON-representation:

{
    "name":"gizmo",
    "category":"widgets",
    "color":"blue",
    "price":10
}

Här är en möjlig JSON-kopplingskorrigering för den här resursen:

{
    "price":12,
    "color":null,
    "size":"small"
}

Den här sammanslagningskorrigeringen uppmanar servern att uppdatera price, ta bort coloroch lägga till size. Värdena för name och category ändras inte. Mer information om JSON-sammanslagningskorrigering finns i RFC 7396. Medietypen för JSON-mergepatch är application/merge-patch+json.

Kopplingskorrigeringen är inte lämplig om den ursprungliga resursen kan innehålla explicita null-värden på grund av den särskilda innebörden av null i korrigeringsdokumentet. Korrigeringsdokumentet anger inte heller i vilken ordning servern ska tillämpa uppdateringarna. Om den här ordningen är viktig beror på data och domänen. JSON-korrigeringen, som definieras i RFC 6902, är mer flexibel eftersom den anger ändringarna som en sekvens av åtgärder som ska tillämpas, inklusive att lägga till, ta bort, ersätta, kopiera och testa för att verifiera värden. Medietypen för JSON-korrigeringen är application/json-patch+json.

En PATCH-begäran ska returnera någon av följande HTTP-statuskoder:

HTTP-statuskod Förnuft
200 (OK) Resursen har uppdaterats.
400 (felaktig begäran) Felaktigt formaterat patchdokument.
409 (konflikt) Korrigeringsdokumentet är giltigt, men ändringarna kan inte tillämpas på resursen i dess aktuella tillstånd.
415 (medietyp som inte stöds) Korrigeringsdokumentformatet stöds inte.

TA BORT begäranden

En DELETE-begäran tar bort resursen vid den angivna URI:n. En DELETE-begäran bör returnera någon av följande HTTP-statuskoder:

HTTP-statuskod Förnuft
204 (INGET INNEHÅLL) Resursen har tagits bort. Processen har hanterats och svarstexten innehåller ingen ytterligare information.
404 (HITTADES INTE) Resursen finns inte.

MIME-resurstyper

Resursrepresentation är hur en resurs som identifieras av URI kodas och transporteras via HTTP-protokollet i ett visst format, till exempel XML eller JSON. Klienter som vill hämta en specifik resurs måste använda URI:n i begäran till API:et. API:et svarar genom att returnera en resursrepresentation av de data som anges av URI:n.

I HTTP-protokollet anges resursrepresentationsformat med hjälp av medietyper, även kallade MIME-typer. För icke-binära data stöder de flesta webb-API:er JSON (medietyp = application/json) och eventuellt XML (medietyp = application/xml).

Rubriken Innehållstyp i en begäran eller ett svar anger resursrepresentationsformatet. I följande exempel visas en POST-begäran som innehåller JSON-data:

POST https://api.contoso.com/orders
Content-Type: application/json; charset=utf-8
Content-Length: 57

{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}

Om servern inte stöder medietypen ska den returnera HTTP-statuskod 415 (Medietyp som inte stöds).

En klientbegäran kan innehålla ett Accept-huvud som innehåller en lista över medietyper som klienten accepterar från servern i svarsmeddelandet. Till exempel:

GET https://api.contoso.com/orders/2
Accept: application/json, application/xml

Om servern inte kan matcha någon av de angivna medietyperna bör den returnera HTTP-statuskod 406 (inte acceptabel).

Implementera asynkrona metoder

Ibland kan en POST-, PUT-, PATCH- eller DELETE-metod kräva bearbetning som tar tid att slutföra. Om du väntar på att det ska slutföras innan du skickar ett svar till klienten, kan det orsaka oacceptabel latens. I det här scenariot bör du överväga att göra metoden asynkron. En asynkron metod bör returnera HTTP-statuskod 202 (godkänd) för att indikera att begäran accepterades för bearbetning men är ofullständig.

Exponera en slutpunkt som returnerar status för en asynkron begäran så att klienten kan övervaka statusen genom att avsöka statusslutpunkten. Inkludera URI:n för statusslutpunkten i platsrubriken för 202-svaret. Till exempel:

HTTP/1.1 202 Accepted
Location: /api/status/12345

Om klienten skickar en GET-begäran till den här slutpunkten ska svaret innehålla den aktuella statusen för begäran. Du kan också inkludera en uppskattad tid till slutförande eller en länk för att avbryta åtgärden.

HTTP/1.1 200 OK
Content-Type: application/json

{
    "status":"In progress",
    "link": { "rel":"cancel", "method":"delete", "href":"/api/status/12345" }
}

Om den asynkrona åtgärden skapar en ny resurs ska statusslutpunkten returnera statuskod 303 (se Övrigt) när åtgärden har slutförts. I 303-svaret inkluderar du en platsrubrik som ger URI:n för den nya resursen:

HTTP/1.1 303 See Other
Location: /api/orders/12345

Mer information finns i Ge asynkront stöd för långvariga begäranden och Asynkront Request-Reply mönster.

Implementera datanumrering och filtrering

Om du vill optimera datahämtning och minska nyttolaststorleken implementerar du datanumrering och frågebaserad filtrering i API-designen. Med de här teknikerna kan klienter endast begära den delmängd av data som de behöver, vilket kan förbättra prestanda och minska bandbreddsanvändningen.

  • Sidnumrering delar upp stora datamängder i mindre, hanterbara segment. Använd frågeparametrar som limit för att ange antalet objekt som ska returneras och offset för att ange startpunkten. Se även till att ange meningsfulla standardvärden för limit och offset, till exempel limit=25 och offset=0. Till exempel:

    GET /orders?limit=25&offset=50
    
    • limit: Anger det maximala antalet objekt som ska returneras.

      Tips/Råd

      För att förhindra överbelastningsattacker bör du överväga att införa en övre gräns för hur många objekt som returneras. Om tjänsten till exempel anger max-limit=25och en klient begär limit=1000kan tjänsten antingen returnera 25 objekt eller ett HTTP-BAD-REQUEST fel, beroende på API-dokumentationen.

    • offset: Anger startindexet för data.

  • Med filtrering kan klienter förfina datamängden genom att tillämpa villkor. API:et kan tillåta att klienten skickar filtret i frågesträngen för URI:n:

    GET /orders?minCost=100&status=shipped
    
    • minCost: Filtrerar beställningar som har en minimikostnad på 100.
    • status: Filtrerar beställningar som har en specifik status.

Överväg följande metodtips:

  • Med sortering kan klienter sortera data med hjälp av en sort parameter som sort=price.

    Viktigt!

    Sorteringsmetoden kan ha en negativ effekt på cachelagringen eftersom frågesträngsparametrar ingår i resursidentifieraren som många cacheimplementeringar använder som nyckel till cachelagrade data.

  • Med fältval för klientdefinierade projektioner kan klienter endast ange de fält som de behöver med hjälp av en fields parameter som fields=id,name. Du kan till exempel använda en frågesträngsparameter som accepterar en kommaavgränsad lista med fält, till exempel /orders?fields=ProductID,Quantity.

Ditt API måste verifiera de begärda fälten för att säkerställa att klienten har åtkomst till dem och inte exponerar fält som normalt inte är tillgängliga via API:et.

Stöd för partiella svar

Vissa resurser innehåller stora binära fält, till exempel filer eller bilder. Överväg att stödja partiell hämtning av stora binära resurser för att lösa problem som orsakas av otillförlitliga och tillfälliga anslutningar och för att förbättra svarstiderna.

För att stödja partiella svar bör webb-API:et ha stöd för Accept-Ranges-huvudet för GET-begäranden för stora resurser. Det här rubriken anger att GET-åtgärden stöder partiella begäranden. Klientprogrammet kan skicka GET-begäranden som returnerar en delmängd av en resurs, som anges som ett intervall med byte.

Överväg också att implementera HTTP HEAD-begäranden för dessa resurser. En HEAD-begäran liknar en GET-begäran, förutom att den endast returnerar DE HTTP-huvuden som beskriver resursen med en tom meddelandetext. Ett klientprogram kan utfärda en HEAD-begäran för att avgöra om en resurs ska hämtas med hjälp av partiella GET-begäranden. Till exempel:

HEAD https://api.contoso.com/products/10?fields=productImage

Här är ett exempel på ett svarsmeddelande:

HTTP/1.1 200 OK

Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 4580

Rubriken Innehållslängd ger resursens totala storlek, och rubriken Accept-Ranges anger att motsvarande GET-åtgärd stöder partiella resultat. Klientprogrammet kan använda den här informationen för att hämta avbildningen i mindre segment. Den första begäran hämtar de första 2 500 byteen med hjälp av range-huvudet:

GET https://api.contoso.com/products/10?fields=productImage
Range: bytes=0-2499

Svarsmeddelandet anger att det här svaret är partiellt genom att returnera HTTP-statuskod 206. Rubriken Innehållslängd anger det faktiska antalet byte som returneras i meddelandetexten och inte resursens storlek. Rubriken Innehållsintervall anger vilken del av resursen som returneras (byte 0-2499 av 4580):

HTTP/1.1 206 Partial Content

Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 2500
Content-Range: bytes 0-2499/4580

[...]

En efterföljande begäran från klientprogrammet kan hämta resten av resursen.

Implementera HATEOAS

En av de främsta orsakerna till att använda REST är möjligheten att navigera i hela resursuppsättningen utan förkunskaper om URI-schemat. Varje HTTP GET-begäran ska returnera den information som behövs för att hitta de resurser som är relaterade direkt till det begärda objektet via hyperlänkar som ingår i svaret. Begäran bör också få information om vilka åtgärder som är tillgängliga för var och en av dessa resurser. Den här principen kallas HATEOAS eller Hypertext som motorn för applikationens tillstånd. Systemet är i själva verket en ändlig tillståndsdator, och svaret på varje begäran innehåller den information som krävs för att flytta från ett tillstånd till ett annat. Ingen annan information ska vara nödvändig.

Anmärkning

Det finns inga allmänna standarder som definierar hur HATEOAS-principen ska modelleras. Exemplen i det här avsnittet illustrerar en möjlig, patentskyddad lösning.

Om du till exempel vill hantera relationen mellan en beställning och en kund kan representationen av en order innehålla länkar som identifierar de tillgängliga åtgärderna för kunden i ordern. Följande kodblock är en möjlig representation:

{
  "orderID":3,
  "productID":2,
  "quantity":4,
  "orderValue":16.60,
  "links":[
    {
      "rel":"customer",
      "href":"https://api.contoso.com/customers/3",
      "action":"GET",
      "types":["text/xml","application/json"]
    },
    {
      "rel":"customer",
      "href":"https://api.contoso.com/customers/3",
      "action":"PUT",
      "types":["application/x-www-form-urlencoded"]
    },
    {
      "rel":"customer",
      "href":"https://api.contoso.com/customers/3",
      "action":"DELETE",
      "types":[]
    },
    {
      "rel":"self",
      "href":"https://api.contoso.com/orders/3",
      "action":"GET",
      "types":["text/xml","application/json"]
    },
    {
      "rel":"self",
      "href":"https://api.contoso.com/orders/3",
      "action":"PUT",
      "types":["application/x-www-form-urlencoded"]
    },
    {
      "rel":"self",
      "href":"https://api.contoso.com/orders/3",
      "action":"DELETE",
      "types":[]
    }]
}

I det här exemplet har matrisen links en uppsättning länkar. Varje länk representerar en åtgärd på en relaterad entitet. Data för varje länk innehåller relationen ("kund"), URI (https://api.contoso.com/customers/3), HTTP-metoden och de MIME-typer som stöds. Klientprogrammet behöver den här informationen för att anropa åtgärden.

Matrisen links innehåller även självrefererande information om den hämtade resursen. Dessa länkar har relationen self.

Den uppsättning länkar som returneras kan ändras beroende på resursens tillstånd. Tanken att hypertext är motorn i programtillståndet beskriver det här scenariot.

Implementera versionshantering

Ett webb-API förblir inte statiskt. När affärskraven ändras läggs nya samlingar av resurser till. När nya resurser läggs till kan relationerna mellan resurserna ändras och strukturen för data i resurser kan ändras. Att uppdatera ett webb-API för att hantera nya eller olika krav är en enkel process, men du måste tänka på vilka effekter sådana ändringar har på klientprogram som använder webb-API:et. Utvecklaren som utformar och implementerar ett webb-API har fullständig kontroll över det API:et, men de har inte samma kontroll över klientprogram som skapats av partnerorganisationer. Det är viktigt att fortsätta att stödja befintliga klientprogram samtidigt som nya klientprogram kan använda nya funktioner och resurser.

Ett webb-API som implementerar versionshantering kan ange de funktioner och resurser som det exponerar, och ett klientprogram kan skicka begäranden som dirigeras till en specifik version av en funktion eller resurs. I följande avsnitt beskrivs flera olika metoder, som var och en har sina egna fördelar och kompromisser.

Ingen versionshantering

Den här metoden är den enklaste och kan fungera för vissa interna API:er. Betydande ändringar kan representeras som nya resurser eller nya länkar. Att lägga till innehåll i befintliga resurser kanske inte medför någon icke-bakåtkompatibel ändring eftersom klientprogram som inte förväntar sig att se det här innehållet ignorerar det.

En begäran till URI https://api.contoso.com/customers/3 :n ska till exempel returnera information om en enskild kund som innehåller fälten id, nameoch address som klientprogrammet förväntar sig:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}

Anmärkning

För enkelhetens skull innehåller exempelsvaren som visas i det här avsnittet inte HATEOAS-länkar.

Om fältet DateCreated läggs till i schemat för kundresursen ser svaret ut så här:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}

Befintliga klientprogram kan fortsätta att fungera korrekt om de kan ignorera okända fält. Under tiden kan nya klientprogram utformas för att hantera det nya fältet. Mer drastiska ändringar av schemat för resurser, inklusive fältborttagningar eller namnbyte, kan dock inträffa. Eller så kan relationerna mellan resurser ändras. Dessa uppdateringar kan utgöra större ändringar som förhindrar att befintliga klientprogram fungerar korrekt. I dessa scenarier bör du överväga någon av följande metoder:

URI-versionshantering

Varje gång du ändrar webb-API:et eller ändrar schemat för resurser lägger du till ett versionsnummer i URI:n för varje resurs. De tidigare befintliga URI:erna bör fortsätta att fungera normalt genom att returnera resurser som överensstämmer med deras ursprungliga schema.

Till exempel omstruktureras fältet address i föregående exempel till underfält som innehåller varje del av adressen, såsom streetAddress, city, state och zipCode. Den här versionen av resursen kan exponeras via en URI som innehåller ett versionsnummer, till exempel https://api.contoso.com/v2/customers/3:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

Den här versionsmekanismen är enkel men är beroende av servern för att dirigera begäran till rätt slutpunkt. Det kan dock bli otympligt eftersom webb-API:et mognar över flera iterationer och servern måste stödja många olika versioner. Från en purists synvinkel hämtar klientprogrammen i alla fall samma data (kund 3), så URI:n bör inte skilja sig åt beroende på versionen. Det här schemat komplicerar även implementeringen av HATEOAS eftersom alla länkar måste inkludera versionsnumret i sina URI:er.

Versionshantering av frågesträngar

I stället för att tillhandahålla flera URI:er kan du ange resursversionen med hjälp av en parameter i frågesträngen som läggs till i HTTP-begäran, till exempel https://api.contoso.com/customers/3?version=2. Versionsparametern bör som standard ha ett meningsfullt värde, till exempel 1, om äldre klientprogram utelämnar det.

Den här metoden har den semantiska fördelen att samma resurs alltid hämtas från samma URI. Den här metoden beror dock på den kod som hanterar begäran för att parsa frågesträngen och skicka tillbaka lämpligt HTTP-svar. Den här metoden komplicerar även implementeringen av HATEOAS på samma sätt som URI-versionsmekanismen.

Anmärkning

Vissa äldre webbläsare och webbproxyservrar cachelagrar inte svar för begäranden som innehåller en frågesträng i URI:n. Osparade svar kan försämra prestandan för webbapplikationer som använder ett webb-API och körs i en äldre webbläsare.

Versionshantering av sidhuvud

I stället för att lägga till versionsnumret som en frågesträngsparameter kan du implementera en anpassad rubrik som anger resursens version. Den här metoden kräver att klientprogrammet lägger till rätt rubrik i alla begäranden. Den kod som hanterar klientbegäran kan dock använda ett standardvärde, till exempel version 1, om versionshuvudet utelämnas.

I följande exempel används en anpassad rubrik med namnet Custom-Header. Värdet för den här rubriken anger versionen av webb-API:et.

Version 1:

GET https://api.contoso.com/customers/3
Custom-Header: api-version=1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}

Version 2:

GET https://api.contoso.com/customers/3
Custom-Header: api-version=2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}

På samma sätt som versionshantering av URI och frågesträngsversioner måste du inkludera lämplig anpassad rubrik i alla länkar för att implementera HATEOAS.

Versionshantering av medietyp

När ett klientprogram skickar en HTTP GET-begäran till en webbserver bör den använda ett Accept-huvud för att ange formatet för det innehåll som det kan hantera. Syftet med rubriken Acceptera är vanligtvis att tillåta klientprogrammet att ange om innehållet i svaret ska vara XML, JSON eller något annat gemensamt format som klienten kan parsa. Det går dock att definiera anpassade medietyper som innehåller information som gör att klientprogrammet kan ange vilken version av en resurs som förväntas.

I följande exempel visas en begäran som anger ett Accept-huvud med värdet application/vnd.contoso.v1+json. Elementet vnd.contoso.v1 anger för webbservern att den ska returnera version 1 av resursen. Elementet json anger att formatet för svarstexten ska vara JSON:

GET https://api.contoso.com/customers/3
Accept: application/vnd.contoso.v1+json

Koden som hanterar begäran ansvarar för att bearbeta accepthuvudet och respektera det så mycket som möjligt. Klientprogrammet kan ange flera format i sidhuvudet Acceptera, vilket gör att webbservern kan välja det lämpligaste formatet för svarstexten. Webbservern bekräftar dataformatet i svarstexten med hjälp av rubriken Innehållstyp:

HTTP/1.1 200 OK
Content-Type: application/vnd.contoso.v1+json; charset=utf-8

{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}

Om sidhuvudet Acceptera inte anger några kända medietyper kan webbservern generera ett HTTP 406-svarsmeddelande (inte acceptabelt) eller returnera ett meddelande med en standardmedietyp.

Den här versionsmekanismen är enkel och passar bra för HATEOAS, som kan innehålla MIME-typen av relaterade data i resurslänkar.

Anmärkning

När du väljer en versionsstrategi har det konsekvenser, särskilt när det gäller cachelagring för webbservrar. Versionshanteringsscheman för URI- och frågesträngsversioner är cachevänliga eftersom samma URI- eller frågesträngskombination refererar till samma data varje gång.

Versionshanteringsmekanismer för rubriker och medietyper kräver vanligtvis mer logik för att undersöka värdena i den anpassade rubriken eller Accept-rubriken. I en storskalig miljö kan många klienter som använder olika versioner av ett webb-API resultera i en betydande mängd duplicerade data i en cache på serversidan. Det här problemet kan bli akut om ett klientprogram kommunicerar med en webbserver via en proxy som implementerar cachelagring och endast vidarebefordrar en begäran till webbservern om den för närvarande inte innehåller en kopia av begärda data i cacheminnet.

Webb-API:er för flera klientorganisationer

En webb-API-lösning för flera klienter delas av flera klienter, till exempel distinkta organisationer som har egna användargrupper.

Multitenancy påverkar webb-API:ets design avsevärt eftersom det avgör hur resurser används och identifieras för flera klienter i ett enda webb-API. Utforma ett API med flera klientorganisationer i åtanke för att undvika behovet av framtida omstrukturering för att implementera isolering, skalbarhet eller klientspecifika anpassningar.

Ett välkonstruerat API bör tydligt definiera hur klienter identifieras i begäranden, antingen via underdomäner, sökvägar, rubriker eller token. Den här strukturen garanterar en konsekvent men flexibel upplevelse för alla användare i systemet. Mer information finns i Mappa begäranden till klienter i en lösning med flera klienter.

Multitenancy påverkar slutpunktsstruktur, hantering av begäranden, autentisering och auktorisering. Den här metoden påverkar också hur API-gatewayer, lastbalanserare och serverdelstjänster dirigerar och bearbetar begäranden. Följande strategier är vanliga sätt att uppnå multitenancy i ett webb-API.

Använd underdomän- eller domänbaserad isolering (DNS-nivå)

Den här metoden dirigerar begäranden med hjälp av klientspecifika domäner. Wildcard-domäner använder underdomäner för flexibilitet och enkelhet. Anpassade domäner, som gör det möjligt för klientorganisationer att använda sina egna domäner, ger större kontroll och kan skräddarsys för att uppfylla specifika behov. Båda metoderna förlitar sig på korrekt DNS-konfiguration, inklusive A och CNAME poster, för att dirigera trafik till lämplig infrastruktur. Jokerteckendomäner förenklar konfigurationen, men anpassade domäner ger en mer varumärkesanpassad upplevelse.

Bevara värdnamnet mellan omvänd proxy och serverdelstjänster för att undvika problem som URL-omdirigering och förhindra att interna URL:er exponeras. Den här metoden säkerställer korrekt routning av klientspecifik trafik och skyddar den interna infrastrukturen. DNS-matchning är avgörande för att uppnå datahemvist och säkerställa regelefterlevnad.

GET https://adventureworks.api.contoso.com/orders/3

Skicka klientspecifika HTTP-huvuden

Klientinformation kan skickas via anpassade HTTP-huvuden som X-Tenant-ID eller X-Organization-ID via värdbaserade rubriker som Host eller X-Forwarded-Host, eller så kan den extraheras från JSON Web Token-anspråk (JWT). Valet beror på routningsfunktionerna för din API-gateway eller omvänd proxy, med huvudbaserade lösningar som kräver en Layer 7-gateway (L7) för att inspektera varje begäran. Det här kravet lägger till bearbetningskostnader, vilket ökar beräkningskostnaderna när trafiken skalar. Men rubrikbaserad isolering ger viktiga fördelar. Det möjliggör centraliserad autentisering, vilket förenklar säkerhetshanteringen för api:er för flera klientorganisationer. Genom att använda SDK:er eller API-klienter hanteras klientkontexten dynamiskt vid körning, vilket minskar konfigurationskomplexiteten på klientsidan. Att behålla klientkontexten i rubriker resulterar också i en renare, mer RESTful API-design genom att undvika klientspecifika data i URI:n.

Ett viktigt övervägande för rubrikbaserad routning är att det komplicerar cachelagring, särskilt när cachelager enbart förlitar sig på URI-baserade nycklar och inte tar hänsyn till rubriker. Eftersom de flesta cachelagringsmekanismer optimeras för URI-sökningar kan förlita sig på huvuden leda till fragmenterade cacheposter. Fragmenterade poster minskar antalet cacheträffar och ökar belastningen på serverdelen. Mer kritiskt är om ett cachelager inte särskiljer svar efter rubriker kan det leverera cachelagrade data avsedda för en hyresgäst till en annan och skapa en risk för dataläckage.

GET https://api.contoso.com/orders/3
X-Tenant-ID: adventureworks

eller

GET https://api.contoso.com/orders/3
Host: adventureworks

eller

GET https://api.contoso.com/orders/3
Authorization: Bearer <JWT-token including a tenant-id: adventureworks claim>

Skicka hyresgästspecifik information genom URI-sökvägen

Den här metoden lägger till klientidentifierare i resurshierarkin och förlitar sig på API-gatewayen eller omvänd proxy för att fastställa lämplig klientorganisation baserat på sökvägssegmentet. Sökvägsbaserad isolering är effektiv, men den äventyrar webb-API:ets RESTful-design och introducerar mer komplex routningslogik. Det kräver ofta mönstermatchning eller reguljära uttryck för att parsa och kanonisera URI-sökvägen.

Däremot förmedlar rubrikbaserad isolering klientinformation via HTTP-huvuden som nyckel/värde-par. Båda metoderna möjliggör effektiv infrastrukturdelning för att sänka driftskostnaderna och förbättra prestandan i storskaliga webb-API:er med flera klientorganisationer.

GET https://api.contoso.com/tenants/adventureworks/orders/3

Aktivera distribuerad spårning och spårningskontext i API:er

I takt med att distribuerade system och mikrotjänstarkitekturer blir standard ökar komplexiteten i moderna arkitekturer. Det är bra att använda rubriker, till exempel Correlation-ID, X-Request-IDeller X-Trace-ID, för att sprida spårningskontext i API-begäranden för att uppnå synlighet från slutpunkt till slutpunkt. Den här metoden möjliggör sömlös spårning av begäranden när de flödar från klienten till serverdelstjänster. Det underlättar snabb identifiering av fel, övervakar svarstid och mappar API-beroenden mellan tjänster.

API:er som stöder inkludering av spårnings- och kontextinformation förbättrar deras observerbarhetsnivå och felsökningsfunktioner. Genom att aktivera distribuerad spårning möjliggör dessa API:er en mer detaljerad förståelse för systembeteende och gör det enklare att spåra, diagnostisera och lösa problem i komplexa miljöer med flera tjänster.

GET https://api.contoso.com/orders/3
Correlation-ID: 0f8fad5b-d9cb-469f-a165-70867728950e
HTTP/1.1 200 OK
...
Correlation-ID: 0f8fad5b-d9cb-469f-a165-70867728950e

{...}

Mognadsmodell för webb-API

År 2008 föreslog Leonard Richardson det som nu kallas Richardson Maturity Model (RMM) för webb-API:er. RMM definierar fyra mognadsnivåer för webb-API:er och baseras på principerna för REST som en arkitekturmetod för att utforma webbtjänster. När mognadsnivån ökar i RMM blir API:et mer RESTful och följer principerna för REST närmare.

Här är nivåerna:

  • Nivå 0: Definiera en URI och alla åtgärder är POST-begäranden till den här URI:n. Webbtjänster för Simple Object Access Protocol är vanligtvis på den här nivån.
  • Nivå 1: Skapa separata URI:er för enskilda resurser. Den här nivån är ännu inte RESTful, men den börjar anpassa sig till RESTful-design.
  • Nivå 2: Använd HTTP-metoder för att definiera åtgärder för resurser. I praktiken överensstämmer många publicerade webb-API:er ungefär med den här nivån.
  • Nivå 3: Använd hypermedia (HATEOAS). Den här nivån är verkligen ett RESTful-API, enligt Fieldings definition.

OpenAPI-initiativ

OpenAPI-initiativet skapades av ett branschkonsortium för att standardisera REST API-beskrivningar mellan leverantörer. Standardspecifikationen kallades Swagger innan den togs med under OpenAPI-initiativet och bytte namn till OpenAPI Specification (OAS).

Du kanske vill använda OpenAPI för dina RESTful-webb-API:er. Tänk på följande:

  • OAS levereras med en uppsättning yttranderiktlinjer för REST API-design. Riktlinjerna är fördelaktiga för samverkan men kräver att du ser till att din design överensstämmer med specifikationerna.

  • OpenAPI främjar en "contract-first"-metod i stället för en implementeringsinriktad metod. Kontrakt först innebär att du utformar API-kontraktet (gränssnittet) först och sedan skriver kod som implementerar kontraktet.

  • Verktyg som Swagger (OpenAPI) kan generera klientbibliotek eller dokumentation från API-kontrakt. Ett exempel finns i dokumentationen om ASP.NET Core-webb-API:et med Swagger/OpenAPI.

Nästa steg