Hopp til hovedinnhold

REST brukes ofte som en samlebetegnelse for HTTP-baserte API-er, men etter Roy Fieldings opprinnelige definisjon stiller arkitekturstilen langt strengere krav. Vi vil drøfte hvorfor HATEOAS er en uunnværlig del av REST, og hvordan hypermedia kan brukes til å styre både flyt og autorisasjon i et grensesnitt.

REST med Hypermedia-styrt tilstand HATEOAS

Begrepet REST kommer fra doktorgradsavhandlingen [1.] til Roy Thomas Fielding fra året 2000. Jeg skal ikke lage en oppsummering av avhandlingen her, men kort fortalt diskuterer han mange forskjellige former for arkitektur over nettverk. Gjennom argumentasjon for at vi trenger en arkitektur-stilart og beskrankninger som passer for web, lander Roy til slutt på noe han kaller Representational State Transfer (REST). REST er en arkitekturstil som er:

Klient-server: Separasjon av ansvar i klient og server er viktig for at system kan utvikle seg uavhengig av hverandre.

Tilstandsløs: Alle kall på en server skal ha all informasjon i seg for at tjenesten skal forstå kallet. Tilstand skal beholdes utelukkende på klienten.

Cache: For å forbedre effektiviteten til nettverket skal alle tjenestesvar markeres som cacheable eller ikke cacheable.

Uniformt grensesnitt: Det sentrale elementet i å skape et uniformt grensesnitt handler om at klienter og tjenesten skal utvikle seg uavhengig av hverandre. For å få til det må tjenesten basere seg på standarder og generelle mønstre. For å oppnå et uniformt grensesnitt har jeg lyst til å sitere Roy Fielding direkte:

In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state.

Roy Thomas Fielding

La oss kjapt gå over disse beskrankningene.

Identification of resources
Vi skal altså ha en unik referanse til en ressurs. Vi kjenner dette som URL-er på web i dag. Husk at en URL kan ha andre protokoller enn http, slik som ftp, tel, mailto osv. URL-en betyr noe for kommunikasjonen og visse a priori regler følger protokollen for hvordan kommunikasjonen skal utføres. http: betyr noe annet enn mailto: og vi vet hva det vil si.

Manipulation of resources through representations
En ressurs vil ha en representasjon. Det gis av MIME-typen. Det kan være ustrukturert som et bilde som jpg eller et dokument som pdf. Eller mer strukturert data som JSON eller XML. I alle tilfeller er det noe som representerer ressursen, det er ikke selve ressursen.

self-descriptive messages
Meldinger skal inneholde all informasjon og bruke standarder for å beskrive seg selv eller inneholde en beskrivelse av seg selv. For eksempel skal en HTTP-melding inneholde Host-header for ressursen samt MIME-typer som beskriver hva slags melding det er. De skal også være frikoblet transportlaget. REST kan i prinsippet også gjøres over asynkron e-post, så lenge meldingene er selvbeskrivende!

hypermedia as the engine of application state
Roy Fielding bruker dette begrepet kun én gang i sin doktoravhanding. Men han snakker mye om hypermedia, som er det nye store med web-en som nettopp har blitt skapt. I en bloggpost [2.] skriver Roy: "In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period." Dette er altså ikke noe vi kan utelate, men hele poenget med REST. Klienten starter på ett eller flere kjente utgangspunkt (entry points) og følger hyperlenker derfra for å navigere og interagere med grensesnittet.

Vi må også huske hvilken verden Roy levde i på 90-tallet. CORBA (Common Object Request Broker Architecture) var utbredt og web-services var helt nye tanker. Det fantes ikke noe web 2.0 og Facebook var enda et tiår i fremtiden. Roy jobbet med å utvikle HTTP/1.1 i et eksponentielt ekspanderende internett og mye av tankene hans var knyttet til å få en spesifikasjon som var gjennomarbeidet, utvidbar og ville tåle tidens tann. Les avhandlingen hans!

Etter Fieldings opprinnelige definisjon er JSON-API-er som følger spesifikasjoner som OpenAPI eller WSDL strengt tatt ikke REST, men representerer et RPC-lignende arkitekturprinsipp. Klienten har jo all informasjon om API-et hos seg og har et krav om å implementere støtte for det grensesnittet.

REST-grensesnitt for å registrere en virksomhet i en tjeneste

Jeg vil vise hvordan vi kan lage et JSON REST-grensesnitt, som både er maskinlesbart og som samtidig kan brukes rett i en nettleser.

Når vi kaller på rotressursen https://registrering.example.com/ med en http GET får vi følgende representasjon:

{
  "_links": [
    {
      "rel": "login",
      "href": "https://registrering.example.com/login?provider=bankid",
      "method": [
        "GET"
      ]
    }
  ],
  "description": "REST-grensesnitt for registrering"
}

Den har en beskrivelse samt et sett hyperlenker med én lenke. Skal vi gjøre noe i grensesnittet må vi tydeligvis logge inn. Om vi trykker på den hyperlenka i nettleseren blir vi via en redirect sendt til BankID-pålogging hos en ekstern tjeneste gjennom OIDC. Denne vil så returnere oss tilbake til rot-ressursen og gi oss et aksess-token som vi skal bruke med header Authorization: Bearer <token> i alle kall.

{
  "_links": [
    {
      "rel": "logout",
      "href": "https://registrering.example.com/logout",
      "method": [
        "GET"
      ]
    },
    {
      "rel": "registrerbare-selskaper",
      "href": "https://registrering.example.com/registrerbare-selskaper",
      "method": [
        "GET"
      ]
    }
  ], 
  "welcome": "Hei, Atle"
}

Vi gjør et GET-kall på relasjonen "registrerbare-selskaper" og får:

{
  "foretak": [
    {
      "navn": "TESTREVISJON AS",
      "orgnummer": "810303641",
      "selskapsform": "AS",
      "_links": [
        {
          "rel": "registrer",
          "href": "https://registrering.example.com/api/registrer/810303641",
          "method": [
            "POST"
          ]
        }
      ]
    }
  ]
}

Når du gjør en POST på URL til `registrer` registrerer du selskapet i tjenesten og vil få en 201 med en location-header tilbake. Gjerne en direktelenke til tjenesten hvor du kan fortsette med onboarding eller ta i bruk tjenesten.Hvis du trykker back til `registrerbare-selskaper` bør tjenesten vite at `registrer` ikke skal utføres mer, så relasjonen kan fjernes og kanskje erstattes med en annen lenke som nå kan ta deg til tjenesten. På denne måten kan vi bruke hyperlenker til å designe flyten i en tjeneste. Det er dette som er HATEOAS (`Hypermedia as the engine of application state`).

I det REST-grensesnittet jeg beskriver over kan vi bytte JSON direkte ut med en annen MIME-type. Jeg kan be om å få det som HTML, f.eks, og da vil vi fort forstå at representasjonene vil kunne ha overskrifter, tekster, lenker og formularer som gjør deg i stand til å, ikke bare lese, men skrive data tilbake. Det er fremdeles REST og HATEOAS.

Autorisasjon gjennom hypermedia

Gjennom å styre hvilke relasjoner du får i svar fra tjenesten kan du styre hvordan en applikasjon skal oppføre seg.I stedet for at klienten må kjenne til hvilke operasjoner en bruker har tilgang til, eksponerer tjenesten kun de relasjonene som er tillatt gitt brukerens rolle og kontekst. Mangler en hyperlenke, er operasjonen ikke tilgjengelig – og klienten trenger ikke vite hvorfor. På denne måten flyttes autorisasjonslogikken fullt og helt til tjenesten, mens klienten forholder seg utelukkende til tilgjengelige relasjoner. Dette reduserer koblingen mellom klient og tjeneste, forenkler klientimplementasjonen og gjør det mulig å endre tilgangsregler uten å måtte oppdatere klienten.

For eksempel: Hvis en bruker ikke har tilgang til å opprette en viss søknadstype, så får ikke vedkommende hyperlenker til å opprette søknaden fra REST-grensesnittet, og da trenger man ikke mer informasjon i klienten (frontend) for å vite om du skal vise den funksjonaliteten eller ikke. Klienten din har dermed ingen URL-er lagret noe sted. Og om en relasjonslenke mangler vil klienten ikke feile, men bare utelate funksjonen.

Konklusjon

REST er ikke et sett med tekniske konvensjoner for HTTP og JSON, men en arkitektur med klare beskrankninger definert av Roy Fielding. En av de viktigste – og mest misforståtte – er HATEOAS: at klientens navigasjon og tilstandsendringer skal styres av hypermedia levert av tjenesten. Uten dette er ikke et grensesnitt REST etter Fieldings definisjon, uavhengig av hvor «REST-aktig» det ellers måtte se ut.

Ved å bruke hyperlenker som bærere av både flyt og autorisasjon holdes ansvaret hos tjenesten. Klienten trenger ikke forhåndskunnskap om tilgjengelige operasjoner, tilgangsnivåer eller tillatte overganger, men forholder seg kun til relasjonene som faktisk er eksponert i øyeblikket. Finnes ikke lenken, finnes ikke operasjonen. Dette gir løsere kobling, enklere klienter og større frihet til å endre både forretningsregler og tilgangsstyring uten å bryte eksisterende klienter.

Liker du innlegget?

Del gjerne med kollegaer og venner