Hypermedia

Hypermedialänkar kan användas i API:er. Dessa informerar API konsumenten vart ytterligare innehåll kan hämtas. Dessa API länkar tillåter konsumenten att lokalisera resurser utan att behöva förstå denna resurs och dess relationer fullt ut. Hypermedia är högsta nivån av mognad (nivå 3) enligt Richardsons Maturity Model, där denna profil har satt implementation som ett BÖR krav och är en förutsättning för att ett API ska kallas RESTful.

För att vara ett hypermedia kompatibelt API ska följande vara uppfyllt:

  • Det finns ett väldefinierat index eller startpunkt för navigering för varje API  som klienten navigerar till för att få tillgång till samtliga resurser.
  • Klienten behöver inte bygga logiken för att sätta samman URL som  används för att utföra olika förfrågningar eller att koda någon slags  affärslogik till svaret.
  • Klienten förstår att det är serversidan som äger processen att sätta giltiga  URL:er.
  • Klienter hanterar URL:er som ogenomskinliga (eng: opaque).
  • API:er som använder hypermedia i sin representation kan sömlöst bli  utökade. När nya metoder introduceras, kan svaren inkluderas med  relevanta HATEOAS länkar. På detta sätta kan klienter ta tillvara på de  inkrementella förbättringar som API:et får över tid. Om ett API till  exempelvis börjar stödja PATCH operationen, kan klienten använda detta  för att delvis uppdatera resursen.

Genom att skicka med dessa länkar underlättar man för klienterna att förstå API:erna. Dock tar det inte bort ansvaret för klienten att förstå vilken data som kan användas för att använda operationerna POST/PUT/PATCH. Ett API SKALL (HYP.01) ge god dokumentation som tydligt beskriver alla länkar, dess relationstyper och de svarsformat som varje URL ger. 

Länkar

Hypermedia liknar navigering på en webbsida, där användarna inte förväntas veta strukturen av hemsidan innan de besöker den. De kan enkelt hitta runt på hemsidan med den inbyggda navigeringen genom länkar.

API:er som inte bidrar med länkar är svårare att använda och förväntar sig att användaren refererar till dokumentationen för att förstå dem eller vid exempelvis felsökning.

Exempel:

GET /foretagsinformation/v2/organisationer
HTTP/1.1 200 OK
Content-Type: application/hal+json
...
{
"_meta": {
"totalRecords": 1,
"page": 1,
"limit": 20,
"count": 1
},
"_links": [{
"href": "/foretagsinformation/v2/organisationer",
"rel": "self"
}],
"organisationslista": [{
"namn": "Aktiebolaget Volvo",
"_links": [{
"href" : "/foretagsinformation/v2/organisationer/5560125790",
"rel": "self",
"method": "GET"
}]
}]
}

HATEOAS

Uttal: HAT-E-OAS

HATEOAS (Hypermedia As The Engine Of Application State) är ett koncept för att erbjuda möjliga funktioner som hyperlänkar kopplad till resurser. Liknande konceptet med länkad hypermedia data, definieras länkarna i svarsdatat, med tillgängliga transaktioner från nuvarande tillstånd till närliggande tillstånd.

Bankexempel:

{
"kontonummer":"12345",
"balans": 100.00,
"_links":[
{"rel": " **insättning**", "href":"/konton/12345/insattning"},
{"rel": " **uttag**", "href":"/konton/12345/uttag"},
{"rel": " **överföring**", "href":"/konton/12345/overforing"}
]
}

Om kontot i exemplet har övertrasserats med 25 så är det enda tillgängliga alternativet insättning:

{
"kontonummer":"12345",
"balans": -25.00,
"_links":[{
"rel": "insättning",
"href":"/konton/12345/insattning"
}]
}

Valet att implementera HATEOAS design in API:er beror på hur redo konsumenterna är att konsumera HATEOAS och hur mycket energi och tid man är redo att lägga på design och implementation.

Hypermedia kompatibla API:er

Ett hypermediakompatibelt API erbjuder konsumenterna en uppsättning transaktionstillstånd att använda.

API metoderna DELETE, PATCH, POST och PUT initierar alla en tillståndsförändring för en resurs. En GET-request SKALL INTE (HYP.02) ändra tillstånd på den resurs som hämtas.

För att kunna erbjuda en bättre upplevelse för API konsumenterna, BÖR (HYP.03) API:er erbjuda en lista på tillståndsförändringar som finns tillgängliga för varje resurs i _links listan.

Ett svar BÖR (HYP.04) returnera relaterade och giltiga länkelement. Ett svar SKALL (HYP.05) också returnera ett länkelement till sig själv, self.

Hypermedia response

Existerande standarder, såsom JSON, ATOM, Collection-JSON, HAL m.fl. BÖR (HYP.06) användas istället för egna format.

Exemplen nedan använder sig av formatet HAL (Content-Type: application/hal+json) som har stöd för länkad data igenom attributet _links).

Nedan följer ett exempel på ett API som exponerar dess operationer och använder HATEOAS gränssnittet:

En klient startar kommunikationen med tjänsten genom att skicka en POST på URL /organisationer. Denna URL stödjer både GET  och POST operationer.

Request

POST https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer
organisationslista: [
{
"namn": "Volvo Bikes AB",
"organisationsnummer": "5568101234",
...
} ]

Response

API:et skapar en ny organisation och returnerar följande länkar till klienten som response

  • En länk till den skapade resurser i headern Location (för att efterleva specifikationen för ett 201 svar)
  • En länk för att hämta den kompletta representationen av organisationen (self länken för  GET)
  • En länk för att ta bort organisationen (DELETE)
  • En länk för att uppdatera organisationen (PUT)
  • En länk för att delvis uppdatera organisationen (PATCH)
HTTP/1.1 201 CREATED
Content-Type: application/hal+json
Location: https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234
...
{
"_links": [
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "self",
"method": "GET"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "delete",
"method": "DELETE"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "replace",
"method": "PUT"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "edit",
"method": "PATCH"
}
]
}

En klient som får detta svar kan spara dessa länkar för senare användning.

För att visa samtliga organisationer gör klienten en GET på URL /organisationer.

Request

GET https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer

API:et svarar med samtliga organisationer i systemet med respektive  self länk.

Response

HTTP/1.1 201 CREATED
Content-Type: application/hal+json
Location: https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234
...
{
"_links": [
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "self",
"method": "GET"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "delete",
"method": "DELETE"
},

{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "replace",
"method": "PUT"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5568101234",
"rel": "edit",
"method": "PATCH"
}
]
}

Klienten kan använda  self länken för varje organisation och får där operationerna som kan genomföras på resursen organisationer.

Request

GET https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5560125790

Response

HTTP/1.1 200 OK
Content-Type: application/hal+json
...
organisationslista: [
{
"namn": "Aktiebolaget Volvo",
"organisationsnummer": "5560125790",
...
"_links": [
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5560125790",
"rel": "self",
"method": "GET"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5560125790",
"rel": "delete",
"method": "DELETE"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5560125790",
"rel": "replace",
"method": "PUT"
},
{
"href": "https://gw.api.bolagsverket.se/foretagsinformation/v2/organisationer/5560125790",
"rel": "edit",
"method": "PATCH"
}
]
}

För att ta bort en organisation, använder klienten URL från länkrelationen "rel": “delete” och genomför operationen med följande URL:

DELETE https://gw.api.bolagsverket.se/foretagsinformation/v1/organisationer/5560125790

Relativa kontra absoluta URL:er

Webbadresserna som genereras av API:et BÖR (HYP.07) vara absoluta webbadresser.‎

Anledningen är att det leder till enkel användning för klienten, så att den aldrig behöver ta reda på rätt bas-URL för en resurs, som behövs för att tolka en relativ URL. RFC 3986 för URL:er anger algoritmen för att bestämma en bas-URL, vilket är ganska komplext. Ett av alternativen för att hitta basadressen är att använda URL:en för den begärda resursen. Eftersom en resurs kan visas under flera webbadresser (till exempel som en del av en samling eller fristående) skulle det vara en betydande overhead för en klient att komma ihåg var han hämtade en representation från. Genom att använda absoluta webbadresser uppstår inte det här problemet. 

API Gateways

‎I ‎‎ett hypermedia svar‎‎, eftersträvas användning av absoluta URL:er (enligt ovan). Om API:er befinner sig bakom ‎‎en API Management lösning‎‎ i form av en API Gateway kommer den faktiska URL:en för (backend) API:et att vara annorlunda än URL som är anropas externt, det vill säga den i API gateway.‎

‎Som regel SKALL (HYP.08) API Management gateway skicka ytterligare en header med i anropet till backend API:et som innehåller API Gateway bas URL:en för det aktuella API:et. Headern SKALL (HYP.09) namnges som forwarded, enligt beskrivningen i ‎‎RFC 7239‎‎. De två parametrarna host och proto är fördefinierade i RFC, men ytterligare parametrar behövs:

 host: Måste innehålla värdnamnet för API-gateway. Detta är värden som en API-klient använder för att faktiskt prata med API:et.‎ 
 proto‎: Det protokoll/schema som ska användas.

‎Tillägg:

  • port: Porten för API-gatewayen. Vanligtvis kan detta antas vara om lika med  port  443; använd  proto  om du avviker från ‎https.
  • prefix: Bas-URL för API på API-gateway, t.ex.  prefix/api/v1   

Exempel‎‎: 

En begäran går till https://api.exempel.se/ingest/v1/bulk/63874638746834, som vidarebefordras till tjänsten i backend. API-gateway måste vidarebefordra den här informationen på följande sätt: 

Forwarded: proto=https;host=api.exempel.se;port=443;prefix=/ingest/v1 

‎Om hypermedia används måste informationen i  forwarded headern användas för att skapa korrekta hypermedialänkar i svaret, så att en API konsument dirigeras till rätt plats.‎

‎Om denna header inte finns BÖR (HYP.10) API backend använda sin egen absoluta bas URL som fallback.‎

Link Description Object

Länkar SKALL (HYP.11) beskrivas med ett Link Description Object schema. Ett Link Description Object schema beskriver varje länks relation. Nedan följer en sammanfattning över de delar som ingår i en Link Description Object.

href

  • Ett värde för href SKALL (HYP.12) ges.
  • Värdet för href SKALL (HYP.13) vara en URL som används för att bestämma målet för den relaterade resursen.
  • Används endast absoluta URL värden för href . Klienter kan spara URL för en länk för att använda senare. Utvecklare SKALL (HYP.14) använda värden från inkommande host headern (t.ex. gw.api.bolagsverket.se) i den absoluta URL:n.

rel

  •  rel står för relation som definieras nedan i Link Relation Type.
  • Värdet av rel indikerar relationens namn i resursen.
  • Ett värde för rel SKALL (HYP.15) anges.

method

  • method identifierar HTTP verbet som SKALL (HYP.16) användas i request-anropet i länken. 
  • Om ingen method anges är GET defaultmetod, men method SKALL (HYP.17) anges.

title

  • title används för att rubricera länken för att på så sätt ge värdefull dokumentation för att enklare förstå länkens syfte. title är inte obligatoriskt.

Link Relation Type

En Link Relation Type agerar identifierare för en länk. Ett API SKALL (HYP.18) tilldela en meningsfull Link Relation Type som entydigt beskriver semantiken för länken. Klienter använder Link Relation Type för att hitta länken att använda från en representation.

När semantiken av en Link Relation Type som önskas användas också återfinns i IANA's lista över standardiserade länkrelationer SKALL (HYP.19) IANA’s typ användas. 

Tabellen nedan beskriver de vanligaste typerna:

Link Relation TypeBeskrivning
selfFörmedlar en identifierare för länkens sammanhang. Vanligen en länk som pekar på resursen själv.
createRefererar till en länk som kan användas för att skapa en ny resurs.
editRefererar till ett ändra (helt eller delvis) representationen identifierad av länken. Använd denna för att representera en PATCH  operation.
deleteAnvänd Extended link relation type för att representera en DELETE operation.
replaceRefererar till att helt uppdatera (eller ersätta) representationen identifierad av länken. Använd Extended link relation type för att representera en PUT operation.
firstRefererar till den första sidan i en resultatlista.
lastRefererar till sista sidan i en resultatlista.
nextRefererar till nästa sida i en resultatlista.
prevRefererar till förra sidan i en resultatlista.
collectionRefererar till en kollektions resurs (t.ex. /v2/organisationer).
latest-versionPekar på en resurs som har senaste (nuvarande) versionen.
searchRefererar till en resurs som kan användas för att söka genom länken kontext och relaterade resurser.
upRefererar till föräldraresursen i en hierarki av resurser.

Vid användande av olika typer av händelser, ska motsvarande händelsenamn användas som Link Relation Type (t.ex.  activatecancelsend, …).