Gå til indholdet

REST API

For at forstå RESTful API’er skal vi først se på, hvordan internettet fungerer. Når du besøger en hjemmeside, sender din browser en anmodning til en server ved hjælp af HTTP-protokollen. Serveren behandler anmodningen og sender et svar tilbage, typisk i form af en webside eller data. Dette grundlæggende princip ligger til grund for næsten al kommunikation på internettet.

Info

Se eventuelt mit eksempel API - MiniCRM hvis du vil lege lidt med REST uden at skrive backend koden.

HTTP/S

HTTP, som står for HyperText Transfer Protocol, blev udviklet i begyndelsen af 1990’erne og har gennemgået flere opdateringer, men de grundlæggende mekanismer er de samme. HTTP fungerer efter en klient-server-model, hvor en klient, som kan være en browser, en mobilapp eller et andet program, sender en anmodning til en server. Serveren behandler anmodningen og returnerer et svar. Det gør HTTP til en stateless protokol, hvilket betyder, at hver anmodning behandles individuelt uden at huske tidligere anmodninger.

Internettet er bygget på denne type kommunikation, og i takt med at flere og flere tjenester har behov for at udveksle data mellem systemer, er der opstået en standard for, hvordan dette bedst gøres – nemlig REST.

Historien bag HTTP/S

Internettets udvikling har været tæt knyttet til udviklingen af HTTP (HyperText Transfer Protocol), som blev skabt for at muliggøre kommunikation mellem klienter og servere. Protokollen har udviklet sig gennem årene for at håndtere nye krav til sikkerhed, hastighed og funktionalitet.

Starten på HTTP (1989-1991)

I slutningen af 1980’erne udviklede den britiske forsker Tim Berners-Lee konceptet for det, der senere blev til World Wide Web. Han arbejdede på CERN og havde brug for en måde at dele dokumenter mellem forskere på tværs af forskellige computere. Dette førte til udviklingen af HTTP samt HTML (HyperText Markup Language) og den første webbrowser.

Den første version af HTTP, kendt som HTTP/0.9, blev udviklet i 1991 og var ekstremt simpel. Den understøttede kun GET-anmodninger og kunne kun hente HTML-dokumenter – ingen billeder, ingen CSS, ingen JavaScript, ingen interaktivitet.

HTTP/1.0 og 1.1 (1996-1999) – Udvidelse af funktionalitet

Efterhånden som internettet voksede, blev der behov for mere funktionalitet. HTTP/1.0, der blev standardiseret i 1996, introducerede flere HTTP-metoder såsom POST og HEAD, samt support for statuskoder og HTTP-headere.

I HTTP/1.1, som blev introduceret i 1999, blev der tilføjet vigtige forbedringer såsom vedvarende forbindelser (keep-alive), hvilket gjorde det muligt at genbruge en enkelt forbindelse til flere anmodninger, hvilket forbedrede hastigheden markant. Desuden blev chunked transfer encoding introduceret, hvilket tillod serveren at sende data i dele, hvilket gjorde streaming af store filer muligt.

Problemet med usikre forbindelser og starten på HTTPS (1994-2000)

Fra starten var HTTP en ukrypteret protokol, hvilket betød, at alle data sendt mellem klienten og serveren kunne aflyttes af tredjepart. Dette var ikke et stort problem i internettets tidlige dage, men med introduktionen af e-handel, online banking og personfølsomme oplysninger blev det nødvendigt at beskytte data.

For at løse dette blev HTTPS (HTTP Secure) introduceret i 1994 af Netscape, som kombinerede HTTP med SSL (Secure Sockets Layer), en krypteringsprotokol, der sikrede, at data blev sendt sikkert over internettet. SSL blev senere erstattet af TLS (Transport Layer Security), som stadig bruges i dag.

I starten blev HTTPS primært brugt på betalingssystemer og login-sider, men i dag bruges det på næsten alle hjemmesider. Google har aktivt promoveret brugen af HTTPS ved at give HTTPS-sider en højere rangering i søgeresultaterne og markere HTTP-sider som usikre i Chrome-browseren.

HTTP/2 (2015) – Hastighedsforbedringer

I 2015 blev HTTP/2 introduceret for at forbedre internettets ydeevne. Det største problem med HTTP/1.1 var, at hver HTTP-anmodning krævede en ny forbindelse, hvilket førte til mange unødvendige forsinkelser. HTTP/2 introducerede multiplexing, som tillod flere anmodninger at blive sendt samtidig over en enkelt forbindelse. Dette reducerede forsinkelser og gjorde websider hurtigere at indlæse.

HTTP/2 blev også designet til at fungere optimalt med HTTPS, hvilket betød, at næsten alle implementeringer af HTTP/2 krævede krypterede forbindelser.

HTTP/3 (2022) – Fra TCP til QUIC

Den nyeste version, HTTP/3, blev godkendt i 2022 og adskiller sig fra sine forgængere ved at skifte fra TCP (Transmission Control Protocol) til QUIC (Quick UDP Internet Connections). TCP har været fundamentet for internettet siden starten, men det kan være langsomt på grund af forsinkelser i forbindelse med fejlhåndtering og bekræftelser. QUIC, som blev udviklet af Google, reducerer disse forsinkelser ved at bruge UDP i stedet for TCP og har indbygget kryptering som standard.

HTTP/3 forbedrer hastigheden yderligere, især på mobile netværk og ustabile forbindelser, hvor TCP kan være ineffektivt.

Fremtiden for HTTP og HTTPS

I dag er HTTPS ikke længere en valgfri funktion, men en nødvendighed. Moderne browsere kræver HTTPS for at tillade visse funktioner, og mange API’er afviser anmodninger, der ikke kommer fra en sikker forbindelse. Med den løbende udvikling af internettet vil vi sandsynligvis se endnu flere forbedringer i HTTP-protokollen, især med fokus på hastighed, sikkerhed og effektivitet.

Fra en simpel tekstbaseret protokol i 1991 til en fuldt krypteret, højtydende løsning i dag har HTTP gennemgået en enorm udvikling. Med HTTP/3 og fremtidige opdateringer vil internettet fortsætte med at blive hurtigere, mere sikkert og mere stabilt.

HTTP kommandoer

Når en klient kommunikerer med en server via HTTP, bruges forskellige kommandoer, også kaldet HTTP-metoder, til at angive, hvad der skal ske med de data, der bliver sendt eller anmodet om.

Den mest almindelige metode er GET, som bruges til at hente data fra serveren. Når en klient sender en GET-anmodning til en bestemt URL, returnerer serveren de ønskede data uden at ændre noget på serveren. GET bruges ofte til at hente lister af data eller detaljer om en enkelt ressource, for eksempel en bruger eller et produkt.

Hvis en klient ønsker at tilføje en ny ressource til serveren, bruges POST. POST-anmodningen indeholder de nødvendige data i anmodningens body, og serveren opretter den nye ressource og returnerer normalt en bekræftelse sammen med en statuskode, der angiver, at ressourcen er blevet oprettet.

Når en eksisterende ressource skal opdateres, bruges PUT eller PATCH. PUT erstatter hele ressourcen med de nye data, mens PATCH kun opdaterer de felter, der er angivet i anmodningen. Begge metoder bruges til at sikre, at data på serveren forbliver ajourførte.

For at fjerne en ressource fra serveren anvendes DELETE. Når en klient sender en DELETE-anmodning til en bestemt URL, sletter serveren den pågældende ressource og returnerer en bekræftelse.

Udover disse grundlæggende metoder understøtter HTTP også metoder som HEAD, der fungerer ligesom GET, men kun returnerer metadata om en ressource uden at sende selve indholdet, samt OPTIONS, som kan bruges til at forespørge serveren om, hvilke metoder der er tilladt for en bestemt ressource.

HTTP-metode Beskrivelse
GET Henter data fra serveren
POST Opretter en ny ressource
PUT Opdaterer en eksisterende ressource (hele objektet)
PATCH Opdaterer en del af en ressource
DELETE Sletter en ressource
HEAD Returnerer kun metadata om ressourcen
OPTIONS Returnerer hvilke metoder der er tilladt for en ressource

HTTP Request og Response

Når en klient kommunikerer med en server via HTTP, sker det gennem en HTTP Request (anmodning), og serveren svarer med en HTTP Response (svar). Disse to elementer danner grundlaget for al kommunikation mellem klienter (som browsere, mobilapps eller API-klienter) og servere.


HTTP Request

En HTTP-anmodning består af tre hoveddele:

  1. Startlinje – Angiver anmodningens type (metode), URL og HTTP-version.
  2. Headers – Indeholder metadata om anmodningen, f.eks. autentificering, indholdstype og cache-indstillinger.
  3. Body (valgfri) – Indeholder data, der sendes til serveren (f.eks. JSON eller form-data i en POST-anmodning).

Her er et eksempel på en HTTP GET Request, hvor klienten beder om en liste af brugere fra en server:

GET /users HTTP/1.1
Host: example.com
Accept: application/json
User-Agent: Mozilla/5.0

Her bruges GET-metoden til at hente data fra /users-endepunktet. Headerne fortæller serveren, at klienten ønsker svaret i JSON-format, og hvilken type klient (browser) der laver anmodningen.

I en HTTP POST Request sendes også en body, som indeholder data:

POST /users HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 75

{
  "name": "John Doe",
  "email": "johndoe@example.com"
}

Her oprettes en ny bruger ved at sende JSON-data til /users-endepunktet. Content-Type: application/json angiver, at body’en indeholder JSON-data.


HTTP Response

Når serveren modtager en anmodning, behandler den den og sender et svar tilbage til klienten. Et HTTP-svar består af:

  1. Startlinje – Indeholder HTTP-version, statuskode og statusbesked.
  2. Headers – Indeholder metadata om svaret, f.eks. indholdstype og cache-information.
  3. Body (valgfri) – Indeholder de faktiske data, som returneres (f.eks. en liste af brugere i JSON-format).

Her er et eksempel på et HTTP Response, der returnerer en liste af brugere:

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

[
  {
    "id": 1,
    "name": "John Doe",
    "email": "johndoe@example.com"
  },
  {
    "id": 2,
    "name": "Jane Doe",
    "email": "janedoe@example.com"
  }
]

Her returnerer serveren statuskoden 200 OK, som betyder, at anmodningen lykkedes, og sender en liste af brugere i JSON-format.

Hvis en ressource ikke findes, kan serveren svare med en 404 Not Found-fejl:

HTTP/1.1 404 Not Found
Content-Type: application/json

{
  "error": "User not found"
}

Serveren kan også returnere 201 Created, hvis en ny ressource blev oprettet, eller 500 Internal Server Error, hvis der opstod en uventet fejl.


HTTP Request og Response udgør grundlaget for, hvordan REST API’er fungerer. Ved at forstå deres struktur og hvordan de kommunikerer, kan man effektivt udvikle, teste og debugge API’er.

HTTP Status koder

Når en server svarer på en HTTP-anmodning, returnerer den en statuskode, der angiver resultatet af anmodningen. Disse statuskoder er inddelt i forskellige kategorier.

Koder i 200-serien angiver, at anmodningen blev håndteret korrekt. Den mest almindelige er 200 OK, som betyder, at alt gik godt, og at svaret indeholder de ønskede data. Hvis en ressource blev oprettet som følge af en POST-anmodning, returnerer serveren normalt 201 Created for at indikere, at den nye ressource er blevet tilføjet succesfuldt.

Hvis en anmodning indeholder fejl, returnerer serveren en statuskode i 400-serien. En 400 Bad Request betyder, at anmodningen er forkert formateret eller indeholder ugyldige data. Hvis en klient forsøger at tilgå en ressource, der ikke findes, returnerer serveren 404 Not Found.

Koder i 500-serien indikerer fejl på serveren. En 500 Internal Server Error betyder, at noget gik galt internt i serveren, mens en 503 Service Unavailable angiver, at serveren midlertidigt er utilgængelig, muligvis på grund af vedligeholdelse.

Statuskode Beskrivelse
200 OK Anmodningen lykkedes, og data returneres
201 Created En ny ressource blev oprettet
204 No Content Anmodningen lykkedes, men der returneres ingen data
400 Bad Request Der er en fejl i anmodningen
401 Unauthorized Adgang nægtet, brugeren er ikke autentificeret
403 Forbidden Adgang nægtet, selvom brugeren er autentificeret
404 Not Found Den ønskede ressource findes ikke
500 Internal Server Error En fejl opstod på serveren
503 Service Unavailable Serveren er midlertidigt utilgængelig

HTTP Headers

HTTP-headere er en central del af HTTP-protokollen og bruges til at sende ekstra information mellem klient og server. En HTTP-anmodning og et HTTP-svar består af tre hoveddele:

  1. Startlinje – Angiver typen af anmodning (GET, POST osv.) og URL’en.
  2. Headers – Indeholder metadata og ekstra information om anmodningen eller svaret.
  3. Body – Indeholder data, der sendes med anmodningen eller svaret (hvis relevant).

Headers bruges blandt andet til at specificere, hvilken type indhold der sendes eller ønskes, hvilken autentificering der anvendes, og hvordan data skal håndteres.

Her er nogle af de mest almindelige HTTP-headere og deres funktioner:

  • Authorization – Bruges til at sende autentificeringsoplysninger, f.eks. en API-nøgle eller et JWT-token:

    Authorization: Bearer eyJhbGciOiJIUzI1...
    
  • Content-Type – Angiver, hvilken type data der sendes i en anmodning eller et svar. For eksempel bruges application/json, når der sendes JSON-data:

    Content-Type: application/json
    
  • Accept – Fortæller serveren, hvilken type data klienten ønsker at modtage. Hvis en klient kun kan håndtere JSON-data, kan den angive:

    Accept: application/json
    
  • User-Agent – Indeholder information om klienten, der sender anmodningen, f.eks. browser eller programnavn:

    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
    
  • Cache-Control – Bruges til at styre cache-håndtering i browsere og mellemservere:

    Cache-Control: no-cache, no-store, must-revalidate
    
  • Origin og Referer – Angiver, hvor en anmodning kommer fra, hvilket er relevant i forbindelse med sikkerhed og CORS:

    Origin: https://example.com
    Referer: https://example.com/page1
    
  • Set-Cookie – Bruges af serveren til at sende en cookie til klienten, som derefter automatisk sendes med efterfølgende anmodninger:

    Set-Cookie: sessionid=abc123; Path=/; HttpOnly
    

HTTP-headere er afgørende for at kunne styre, hvordan API’er håndterer anmodninger og svar, især når det gælder autentificering, sikkerhed, og dataformater. Når man udvikler REST API’er, er det vigtigt at have styr på disse headere for at sikre, at API’et fungerer korrekt og sikkert.

HTTP Query string

Når man arbejder med REST API’er, er det ofte nødvendigt at sende ekstra informationer med en anmodning. En af de mest almindelige måder at gøre dette på er via en query string, som er en del af URL’en.

En query string består af nøgle-værdi-par, som tilføjes til URL’en efter et spørgsmålstegn ?. Hvis der er flere parametre, adskilles de med et &-tegn.

For eksempel, hvis man vil hente en liste af brugere, men kun dem der bor i Danmark, kan man sende en GET-anmodning til:

GET /users?country=Denmark

Her er country=Denmark en query string, der filtrerer resultaterne. Man kan også kombinere flere parametre, for eksempel:

GET /users?country=Denmark&age=30

Her beder klienten om at få en liste af brugere, der både bor i Danmark og er 30 år gamle.

Query strings bruges typisk til at filtrere, sortere eller paginere data i API’er. De kan også bruges til søgninger, hvor en bruger for eksempel søger efter produkter ved at skrive en forespørgsel som:

GET /products?search=computer

Dette ville returnere en liste af produkter, der matcher ordet “computer”.

HTTPS

HTTPS står for HyperText Transfer Protocol Secure og er en sikker udvidelse af HTTP-protokollen. Forskellen mellem HTTP og HTTPS ligger i, at al kommunikation mellem klienten og serveren krypteres, så data ikke kan aflæses eller ændres af tredjepart.

Internettet startede oprindeligt med ren HTTP, hvor al data blev sendt i klartekst. Det betød, at hvis en bruger loggede ind på en hjemmeside, kunne en ondsindet tredjepart opsnappe login-oplysningerne, hvis de befandt sig på samme netværk. Dette gjorde HTTP usikkert, især for følsomme data som adgangskoder, kreditkortoplysninger og personlige oplysninger.

For at løse dette problem blev HTTPS introduceret, som benytter SSL/TLS (Secure Sockets Layer / Transport Layer Security) til at kryptere kommunikationen mellem klient og server. Når en bruger besøger en HTTPS-beskyttet side, etableres en sikker forbindelse, hvor data krypteres, så den ikke kan læses af andre.

Når en browser kommunikerer med en server via HTTPS, sker følgende proces:

  1. Klienten (browseren) kontakter serveren og beder om en sikker forbindelse.
  2. Serveren sender et digitalt certifikat (SSL-certifikat), som indeholder en offentlig nøgle og bekræfter, at serveren er autentisk.
  3. Klienten validerer certifikatet for at sikre, at det er udstedt af en betroet certifikatmyndighed (CA - Certificate Authority).
  4. Klienten og serveren opretter en krypteret forbindelse ved hjælp af en TLS-handshake.
  5. Herefter sendes al kommunikation krypteret, så ingen udenforstående kan læse eller manipulere dataene.

En simpel måde at se, om en hjemmeside bruger HTTPS, er ved at kigge i browserens adressefelt. Hvis der er en hængelås ved siden af webadressen, betyder det, at forbindelsen er sikker.

Hvorfor er HTTPS vigtigt?

Brugen af HTTPS er blevet standard på internettet af flere grunde:

  • Sikkerhed: Beskytter brugernes data mod at blive opsnappet af hackere.
  • Integritet: Sikrer, at data ikke ændres undervejs, hvilket forhindrer “man-in-the-middle”-angreb.
  • Autenticitet: Giver sikkerhed for, at man kommunikerer med den rigtige server og ikke en forfalsket kopi.
  • SEO-fordele: Google prioriterer HTTPS-websites højere i søgeresultaterne, fordi de er mere sikre.

I REST API’er er HTTPS afgørende, når API’et håndterer følsomme oplysninger som login-data eller betalingsoplysninger. Uden HTTPS kan en angriber nemt opsnappe API-anmodninger og se, hvilke data der sendes frem og tilbage mellem klienten og serveren.

Når man hoster et REST API, bør man altid sørge for, at det kun accepterer HTTPS-anmodninger. I ASP.NET Core kan man for eksempel tvinge HTTPS ved at konfigurere middleware i Program.cs eller i serveropsætningen.

I dag kræver mange browsere og API-klienter, at der anvendes HTTPS, især hvis der arbejdes med autentificering eller betalingstjenester. Flere tjenester som Let’s Encrypt tilbyder gratis SSL-certifikater, hvilket gør det nemt for udviklere at beskytte deres API’er uden ekstra omkostninger.

Kort sagt er HTTPS ikke længere en valgfri funktion – det er en nødvendighed for ethvert REST API eller webapplikation, der ønsker at sikre brugerdata og opretholde en professionel standard.

En cookie er en lille tekstfil, som en server gemmer i en klients browser for at kunne huske oplysninger på tværs af anmodninger. Cookies bruges typisk til at gemme sessionsdata, autentificeringsoplysninger og præferencer for en bruger.

Når en bruger logger ind på en webapplikation, kan serveren sende en cookie tilbage til klienten som en del af HTTP-svaret. Browseren gemmer denne cookie og sender den automatisk med alle fremtidige anmodninger til samme server.

For eksempel, når en bruger logger ind på en hjemmeside, kan serveren sende følgende svar:

Set-Cookie: sessionid=abc123; Path=/; HttpOnly

Dette betyder, at klienten nu har en cookie med en sessions-id, der kan bruges til at identificere brugeren uden at de skal logge ind igen.

Når brugeren senere besøger hjemmesiden, sendes cookien automatisk med anmodningen:

GET /dashboard
Cookie: sessionid=abc123

Serveren kan derefter bruge denne information til at genkende brugeren og give dem adgang til deres personlige oplysninger.

Cookies kan konfigureres til at have en levetid, for eksempel ved at sætte en expiration date, så de slettes automatisk efter en vis periode. De kan også være HttpOnly, hvilket betyder, at de ikke kan tilgås af JavaScript i browseren, hvilket gør dem mere sikre mod angreb.

I moderne webudvikling bruges cookies ofte til autentificering og sessionstyring, men de kan også bruges til at gemme brugerpræferencer, som for eksempel hvilke sprogindstillinger en bruger har valgt på en hjemmeside.

For mere sikkerhed i REST API’er bruges dog ofte JWT (JSON Web Tokens) i stedet for cookies til autentificering, især i systemer med mobilapps eller tredjepartsintegrationer, hvor cookies ikke er praktiske.

Dataformater (JSON/XML)

Når man arbejder med REST API’er, er det nødvendigt at sende og modtage data i et struktureret format. De mest anvendte formater er JSON (JavaScript Object Notation) og XML (Extensible Markup Language).

JSON vs. XML

JSON er i dag det mest udbredte format til REST API’er, mens XML tidligere blev anvendt i SOAP-baserede webservices. JSON har flere fordele, som har gjort det til standardvalget i moderne REST API’er:

Egenskab JSON XML
Læselighed Simpel og letforståelig syntaks Mere verbos med mange tags
Dataoverhead Mindre, færre tegn Større, da tags gentages
Parsing Hurtig, indbygget i JavaScript Tungere, kræver XML-parser
Standarder ECMA-404, JSON Schema W3C XML, XML Schema (XSD) for validering
Kompleksitet Let at bruge, men understøtter ikke metadata Understøtter komplekse strukturer og namespaces
Brug i API’er Næsten alle moderne REST API’er Bruges mest i ældre systemer og enterprise-løsninger

Eksempler

Her er et eksempel på, hvordan samme data kan repræsenteres i JSON og XML:

JSON
{
  "person": {
    "name": "John Doe",
    "age": 30,
    "email": "john.doe@example.com",
    "addresses": [
      {
        "type": "home",
        "street": "123 Main St",
        "city": "Copenhagen"
      },
      {
        "type": "work",
        "street": "456 Office St",
        "city": "Aarhus"
      }
    ]
  }
}
XML
<person>
  <name>John Doe</name>
  <age>30</age>
  <email>john.doe@example.com</email>
  <addresses>
    <address type="home">
      <street>123 Main St</street>
      <city>Copenhagen</city>
    </address>
    <address type="work">
      <street>456 Office St</street>
      <city>Aarhus</city>
    </address>
  </addresses>
</person>

Udover forskellene i syntaks og læselighed er der også forskelle i dataoverhead. JSON-repræsentationen af ovenstående data fylder 253 bytes, mens XML-versionen fylder 323 bytes.

Dette skyldes, at XML kræver åbningstag og lukningstag for hver enkelt værdi, mens JSON bruger en mere kompakt notation med {} og [].

Standarder

Begge formater er baseret på veldefinerede standarder:

  • JSON er defineret af ECMA-404 (Ecma International) og bruges bredt i webteknologier, inklusive JavaScript. Derudover kan JSON Schema anvendes til validering af JSON-data.
  • XML er en W3C-standard (World Wide Web Consortium), der har eksisteret siden 1998. XML understøtter validering via DTD (Document Type Definition) og XML Schema (XSD), hvilket sikrer en mere stringent struktur.

Serialisering

Serialisering er processen, hvor data eller objekter konverteres til et format, der kan gemmes eller overføres, og derefter rekonstrueres senere. I moderne programmeringssprog anvendes serialisering primært til at konvertere komplekse datastrukturer, såsom objekter, til tekst- eller binærformater, der kan sendes via netværk, gemmes i filer eller databaser.

Tip

Se også afsnittet om Serialisering.

I konteksten af REST API’er er serialisering vigtig, fordi data ofte sendes mellem klient og server i et format som JSON eller XML. Når en applikation skal sende data, serialiseres objekterne til et af disse formater. Når den modtager data, skal de deserialiseres tilbage til objektform, så programmet kan arbejde med dem.

Eksempel på serialisering i C# ved hjælp af JSON:

using System.Text.Json;

var person = new Person { Name = "John", Age = 30 };
string json = JsonSerializer.Serialize(person);
Console.WriteLine(json); // {"Name":"John","Age":30}

Eksempel på deserialisering:

Person person = JsonSerializer.Deserialize<Person>(json);
Console.WriteLine(person.Name); // John

Uden serialisering ville det være vanskeligt at sende komplekse data mellem systemer, da man manuelt skulle konvertere objekter til tekststrenge og håndtere strukturen selv.

I moderne programmeringssprog er serialisering en central del af dataudveksling, især når der arbejdes med API’er, mikroservices, datafiler eller cache-løsninger.

CORS

CORS (Cross-Origin Resource Sharing) er en sikkerhedsmekanisme, der styrer, hvordan en browser håndterer HTTP-anmodninger på tværs af forskellige domæner.

Moderne webbrowsere håndhæver en Same-Origin Policy, hvilket betyder, at en webapplikation kun kan foretage HTTP-anmodninger til det samme domæne, som den blev indlæst fra. Hvis en frontend-applikation kører på http://example.com, kan den som udgangspunkt ikke sende anmodninger til http://api.anotherdomain.com, medmindre serveren eksplicit tillader det via CORS.

Det er vigtigt at forstå, at CORS kun gælder for anmodninger sendt fra browsere. Andre typer klienter, såsom terminalbaserede værktøjer (cURL, Postman) eller programmer skrevet i Python, C#, eller andre sprog, er ikke underlagt denne begrænsning. De kan som udgangspunkt sende anmodninger til ethvert domæne uden problemer.

I REST API’er er CORS vigtigt, fordi API’er ofte bruges af forskellige klienter, såsom webapplikationer, mobilapps og tredjepartsintegrationer. Hvis et API ikke er korrekt konfigureret til at håndtere CORS, kan legitime webklienter opleve fejl, hvor browseren blokerer deres anmodninger, selvom de har den rette autorisation.

Servere kan specificere, hvilke domæner der må foretage anmodninger, samt hvilke HTTP-metoder og headers der er tilladt. CORS er derfor en balance mellem sikkerhed og fleksibilitet, hvor man beskytter brugere mod potentielle angreb, samtidig med at API’et kan tilgås af autoriserede webklienter.

Værktøjer til test og debugging

Når man udvikler og tester REST API’er, er det vigtigt at kunne sende anmodninger til API’et og analysere svarene. Der findes flere værktøjer, der kan hjælpe med dette.

Et af de mest anvendte værktøjer er Postman , som er et grafisk program, hvor man nemt kan oprette og sende HTTP-anmodninger, ændre parametre og headers, samt se serverens svar i et overskueligt format.

For dem, der foretrækker kommandolinjeværktøjer, er cURL et godt alternativ. Med cURL kan man sende HTTP-anmodninger direkte fra terminalen. Hvis man for eksempel vil hente data fra en server, kan man skrive en kommando som curl -X GET http://localhost:5000/users.

Visual Studio Code understøtter også test af REST API’er gennem såkaldte .http-filer. Man kan skrive en anmodning direkte i en fil og sende den med et enkelt klik. Dette gør det let at gemme og genbruge testanmodninger.

Værktøj Beskrivelse Link
Postman Et grafisk program til at oprette og sende HTTP-anmodninger, ændre parametre og headers, samt se serverens svar i et overskueligt format. Postman
cURL Et kommandolinjeværktøj til at sende HTTP-anmodninger direkte fra terminalen. cURL
Visual Studio Code Understøtter test af REST API’er gennem .http-filer, hvor man kan skrive en anmodning direkte i en fil og sende den med et enkelt klik. Visual Studio Code og Test Client
Swagger Et værktøj til at dokumentere og teste API’er direkte i browseren. Swagger
Insomnia Et brugervenligt værktøj til at teste og debugge RESTful API’er. Insomnia

Disse værktøjer gør det nemt at teste og debugge API’er, hvilket er afgørende for at sikre, at de fungerer korrekt og opfylder kravene.

Om REST

REST (Representational State Transfer) er en arkitekturstil til design af netværksbaserede applikationer, hvor data tilgås og manipuleres via enkle og veldefinerede principper. REST blev formelt beskrevet af Roy Fielding i år 2000 og er i dag den mest anvendte metode til at opbygge API’er, der kommunikerer via internettet.

Grundidéen bag REST er, at data på en server organiseres i ressourcer, som kan tilgås via unikke URL’er. En webshop kan for eksempel have et REST API, hvor alle produkter kan hentes fra /products, mens et specifikt produkt findes på /products/42.

REST API’er fungerer ved at udnytte HTTP-metoder til at håndtere ressourcer. Klienten sender en HTTP-anmodning til en bestemt URL, og serveren returnerer data i et format som JSON eller XML. REST gør brug af HTTP-metoder til at definere, hvordan data skal håndteres, hvilket gør kommunikationen intuitiv og velstruktureret.

Mikroservices

Mikroservices er en arkitekturmodel, hvor en applikation opdeles i små, selvstændige tjenester, der hver har ansvaret for én specifik del af systemet. Disse tjenester kommunikerer ofte via REST API’er, hvilket gør REST til en fundamental byggesten i mikroservice-arkitekturer.

I en monolitisk arkitektur er hele systemet samlet i én stor applikation, hvor alle komponenter er tæt forbundne. Dette kan gøre det svært at vedligeholde og skalere applikationen. I en mikroservice-arkitektur opdeles applikationen i flere små services, som hver har sin egen database og funktionalitet.

REST API’er bruges i mikroservices til at:

  • gøre tjenester uafhængige, så hver service har sit eget REST API og systemet bliver løst koblet
  • muliggøre skalerbarhed, da hver mikroservice kan skaleres individuelt uden at påvirke resten af systemet
  • understøtte polyglot udvikling, hvor hver mikroservice kan udvikles i forskellige programmeringssprog og teknologier, så længe de kommunikerer via HTTP og REST
  • gøre fejlhåndtering enklere, da én mikroservice kan fejle uden at påvirke hele systemet

Eksempel på en monolitisk arkitektur:

graph TD;
    A[Brugerforespørgsel] --> B[Stor monolitisk applikation];
    B --> C[Database];

Eksempel på en mikroservice-arkitektur:

graph TD;
    A[Brugerforespørgsel] --> B[API Gateway];
    B --> C[Bruger-service];
    B --> D[Ordre-service];
    B --> E[Betalings-service];

Hver af disse services har sit eget REST API og kan være placeret på forskellige servere eller containere, f.eks. i Docker eller Kubernetes.

REST er dog ikke den eneste kommunikationsmetode for mikroservices. I nogle tilfælde kan gRPC eller asynkron messaging som Kafka eller RabbitMQ være mere velegnet, men REST er ofte det foretrukne valg, da det er simpelt, letforståeligt og bredt understøttet.

Hvordan bruges HTTP-metoder i REST API’er?

I et REST API bruges de forskellige HTTP-metoder til at arbejde med ressourcer. Tabellen nedenfor viser, hvordan de typisk anvendes:

HTTP-metode Formål Eksempel på brug
GET Henter data fra serveren uden at ændre noget GET /products → Hent alle produkter
POST Opretter en ny ressource på serveren POST /products → Opret et nyt produkt
PUT Opdaterer en eksisterende ressource (hele objektet) PUT /products/42 → Erstat produktet med ID 42 med nye data
PATCH Opdaterer en del af en ressource PATCH /products/42 → Opdater kun prisen på produktet med ID 42
DELETE Sletter en ressource DELETE /products/42 → Slet produktet med ID 42

GET er den mest brugte metode og anvendes, når klienten skal hente data fra serveren, f.eks. en liste af produkter eller detaljer om et bestemt produkt. POST bruges, når klienten ønsker at oprette en ny ressource, f.eks. tilføje et nyt produkt i databasen. PUT og PATCH bruges til at opdatere eksisterende data, hvor PUT erstatter hele ressourcen, mens PATCH kun ændrer de specifikke felter, der er angivet. DELETE anvendes til at fjerne en ressource fra systemet.

REST er blevet populært, fordi det er simpelt, fleksibelt og skalerbart. Det bruges bredt i webapplikationer, mobilapps, mikroservices og cloud-baserede systemer, hvor der er behov for at tilgå og manipulere data på en ensartet måde. Ved at følge REST-principperne kan API’er let integreres på tværs af forskellige platforme og teknologier.

OpenAPI, Swagger og API-klienter

Når man arbejder med REST API’er, er det vigtigt at kunne dokumentere og teste dem effektivt. OpenAPI er en standard til beskrivelse af API’er, som gør det muligt at definere API-endpoints, dataformater, parametre og svarstrukturer i en maskinlæsbar specifikation.

OpenAPI og Swagger

OpenAPI blev oprindeligt udviklet som Swagger af SmartBear Software og blev senere en officiel standard under OpenAPI Initiative. Swagger er stadig et populært værktøjssæt, der bruges til at generere OpenAPI-specifikationer, samt til at dokumentere og teste API’er.

Et eksempel på en OpenAPI-specifikation i YAML-format:

openapi: 3.0.0
info:
  title: Eksempel API
  version: 1.0.0
paths:
  /users:
    get:
      summary: Hent en liste af brugere
      responses:
        "200":
          description: Succes
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                    name:
                      type: string

Swagger UI kan visualisere denne OpenAPI-specifikation som en interaktiv API-dokumentation, hvor udviklere kan teste endpoints direkte fra en browser.

Microsoft har fornyligt droppet Swagger som default klient - se https://codewithmukesh.com/blog/dotnet-swagger-alternatives-openapi/.

Autogenerering af klienter

En af de store fordele ved OpenAPI-specifikationer er, at de kan bruges til at autogenerere klientkode i forskellige programmeringssprog. Dette gør det lettere at integrere API’et i forskellige systemer uden at skulle skrive HTTP-anmodninger manuelt.

Eksempler på værktøjer, der understøtter autogenerering af klienter:

  • NSwag – Bruges i .NET til at generere C#-klienter baseret på OpenAPI-specifikationer.
  • OpenAPI Generator – Understøtter over 50 programmeringssprog, herunder Java, C#, Python, TypeScript og Go.
  • Swagger Codegen – Genererer klientbiblioteker for en række sprog og frameworks.

Eksempel på generering af en C#-klient med NSwag:

nswag openapi2csclient /input:api-spec.json /output:ApiClient.cs

Dette vil generere en C#-klasse, der kan bruges til at kalde API’et direkte, uden at udvikleren behøver at håndtere HTTP-anmodninger manuelt.

Autogenererede klienter sparer tid, reducerer fejl og sikrer, at API-integrationer altid er i overensstemmelse med den nyeste API-specifikation.

Autentificering og sikkerhed i REST API’er

Et offentligt REST API, som alle kan tilgå uden restriktioner, er sjældent en god idé. De fleste API’er kræver en eller anden form for autentificering for at sikre, at kun autoriserede brugere kan få adgang til data. Dette kan gøres på forskellige måder.

En af de enkleste metoder er at bruge API-nøgler, hvor klienten skal sende en unik nøgle med hver anmodning for at få adgang til API’et. En mere avanceret metode er OAuth 2.0, som bruges af mange moderne webservices og giver mulighed for at logge ind via tredjepartstjenester som Google eller Facebook. En tredje metode er JWT (JSON Web Tokens), hvor en bruger logger ind og får udstedt et token, som sendes med efterfølgende anmodninger.

Når et API eksponerer følsomme data, er det også vigtigt at anvende HTTPS i stedet for HTTP, så dataoverførslen er krypteret.

MiniCrm

Der ligger et fuldt “CRM” system som en REST app på devcronberg/minicrm - den vil være et godt udgangspunkt for leg med REST.

Simpelt eksempel

ASP.NET Core 8 tilbyder en strømlinet måde at oprette RESTful APIs gennem “minimal APIs”. Denne tilgang fokuserer på enkelhed og reducerer boilerplate-koden betydeligt sammenlignet med tidligere versioner.

Oprettelse af et Minimal API

Her er et eksempel på, hvordan du kan oprette et minimalt API med C# 12 og ASP.NET Core 8:

Brug følgende kommando på terminalen til at oprette et nyt projekt:

dotnet new webapi -minimal -o MyApi

Her efter kan du prøve det af (fra MyApi-mappen) med

dotnet run

og derefter åbne en browser på den URL der fremgår af terminalen /swagger - evt http://localhost:5381/swagger

  • Opret et projekt af typen ASP.NET Core Web Api
    • Se evt her hvis du ikke kan finde projektet
  • Sørg for at der ikke er kryds i “Configure for https” og “Use controllers” hvis du vil have den helt simple måde at skabe et API
  • Tryk på F5.
  • Nu burde du kunne se et Swagger interface