# API

## Vad det är

API, förkortning för application programming interface, är den publicerade uppsättning operationer
som ett program erbjuder andra program: vad varje operation heter, vad den tar emot, vad den
returnerar och hur den rapporterar problem. I bestämd form heter det API:et och i plural API:er. Den
som anropar lär sig den ytan och ingenting bakom den, så programmet på andra sidan kan skrivas om,
flyttas till en annan maskin eller delas upp i tre, och anroparen fortsätter att fungera så länge
ytan håller.

Ordet täcker flera skikt. Ett biblioteks API är de funktioner och typer som det exporterar, och de
anropas inuti en och samma process. Ett operativsystems API är dess systemanrop, och POSIX
standardiserar en gemensam kärna av dem, så att ett program som skrivs mot `open` och `read` går att
bygga på mer än en Unix-liknande systemkärna. Ett webb-API erbjuds över ett nätverk, nästan alltid
över HTTP, och det är vad de flesta menar med ordet i dag: en server som besvarar förfrågningar på
adresser som `/v1/orders`, oftast med JSON i kroppen.

Webb-API:er finns i en handfull stilar. De resursorienterade, ofta kallade REST-liknande, ger varje
sak en adress och använder HTTP:s metoder för att läsa och ändra den. De RPC-liknande, som gRPC,
publicerar namngivna procedurer vars argument och resultat deklareras i förväg. GraphQL erbjuder en
enda endpoint och ett schema, och klienten skriver en fråga som namnger exakt de fält den vill ha
tillbaka. Webhooks vänder på riktningen: när något händer anropar leverantören en adress som kunden
har registrerat.

Tre närliggande ord blandas ofta ihop med API. Ett nätverksprotokoll, som HTTP, bestämmer hur
meddelanden färdas, medan ett API är det som en viss tjänst säger med hjälp av protokollet. Ett SDK
är ett bibliotek i ett visst programspråk som kapslar in någons API, så att en utvecklare anropar en
funktion i stället för att sätta ihop förfrågningar själv. Och implementationen är koden bakom
API:et, som den som anropar aldrig behöver läsa.

## Varför det spelar roll

Ett API är den del av ett system som andra bygger vidare på, och det gör det till ett löfte som
lever längre än koden bakom det. Att skriva om en handler tar en eftermiddag. Att ändra vad samma
handler returnerar kan få en app som redan är installerad i kundernas telefoner att sluta fungera,
liksom en partners nattliga import eller ett skript som ingen längre minns att någon skrev.

Det första beslutet handlar därför om publiken. Ett privat API, som bara teamets egen frontend
använder, kan ändras i samma pull request som sin enda klient. Ett publikt API ändras genom
utfasning och förvarning, och varje fält som det levererar är ett fält att stödja så länge någon
läser det.

Det andra beslutet gäller hur strikt kontraktet är. Ett strikt API deklarerar en typ och en gräns
för varje indata, avvisar det som det inte känner igen och besvarar varje misslyckande med en exakt
statuskod. Det fångar misstag vid dörren och är lättare att dokumentera, testa och generera klienter
för. Ett tillåtande API tar emot vad som än kommer och gör sitt bästa, vilket känns vänligt den
första månaden och sedan gör varje tillfällighet i implementationen till ett beteende som någon är
beroende av. Stränghet kostar designtid i början. Det tillåtande kostar mer senare, vid en tidpunkt
som ingen själv väljer.

Det tredje beslutet gäller andras API:er. En betaltjänst, en karttjänst eller en språkmodell är ett
API som produkten anropar men inte styr över: priser ändras, versioner pensioneras och kvoter
stramas åt. Den som anropar en leverantör direkt från femtio ställen i koden gör ett byte av
leverantör till en omskrivning. Den som anropar den från en enda modul som teamet äger gör bytet
till en ändring i den modulen. Omslaget kostar lite indirektion och köper en väg ut.

Semantic Versioning ger löftet ett ordförråd: huvudversionen räknas upp när det publika API:et
ändras på ett sätt som inte är bakåtkompatibelt, så att en klient kan avgöra enbart utifrån
versionsnumret om en uppgradering är säker. Över HTTP finns flera ställen där ett sådant brott kan
signaleras, och RFC 9205, IETF:s vägledning för protokoll som byggs ovanpå HTTP, räknar bl.a. upp en
ny länkrelation, en ny medietyp och ett nytt header-fält.

## Så ser det ut i praktiken

API:erna bakom flera projekt på den här webbplatsen formades av en och samma fråga: vad hör hemma i
API:et, och vad hör hemma någon annanstans?

På en maritim plattform för professionellt nätverkande, företagsrecensioner och sponsrad utbildning
[hölls Go-API:et medvetet tunt](/sv/portfolio/architected-a-layered-maritime-platform-separating-a-next-57/).
Det är byggt med Huma ovanpå Fiber, och det routar, validerar förfrågan, tillämpar
säkerhetsfiltreringen och orkestrerar, men innehåller ingen affärslogik alls. Reglerna ligger i
PostgreSQL-funktioner, så när en regel ändras sker det i ett lager, i SQL. Gränserna skrevs ned och
upprätthölls sedan i kodgranskningen. Sidan kallar resultatet en tråkig adapter, i ordets goda
bemärkelse.

Ett närliggande projekt flyttade även formningen av svaren ut ur API:et.
[PostgreSQL-funktioner sätter ihop varje svar som JSON](/sv/portfolio/designed-a-json-passthrough-architecture-where-postgresql-functions-58/),
och Go-handlern tar emot det som `json.RawMessage` och vidarebefordrar det orört, genom en liten
hjälpfunktion som heter `QueryJSON`. DTO:erna, mappningsfunktionerna och svars-structarna som ett
lagerindelat API brukar samla på sig föll bort, handlerkoden blev dramatiskt kortare och frontenden
slutade vara kopplad till Go. Avvägningen är värd att nämna: formen på API:ets svar definieras nu i
SQL, och det är där en granskare läser kontraktet.

Ett API som vem som helst kan nå måste också kunna försvara sig. En publik katalog över företag och
yrkespersoner skyddas av
[22 anropsbegränsare, var och en byggd för den väg den skyddar](/sv/portfolio/built-fail-closed-abuse-controls-and-rate-limiting-100/),
med sitt tillstånd i Redis så att en gräns delas mellan instanser. När Redis inte går att nå
stänger begränsarna vid fel och nekar trafiken. Cloudflare Turnstile, ett ursprungslås, en
specialbyggd utmaning på själva katalogen och 351 rader middleware för idempotens, som hindrar att
en skrivning som görs om landar två gånger, fullbordar försvaret. Sidan anger kostnaden rakt ut: ett
Redis-problem blir ett problem som användarna ser, och det valdes hellre än att ett Redis-problem
blir ett faktureringsproblem.

## Var det går fel

Ett API går oftast sönder sent, när klienterna och datan väl har vuxit.

**Ett omdöpt fält slår ut en klient som ingen kände till.** När ett API väl är publicerat är någon
beroende av varje detalj som går att observera: fältnamn, ordningen i en lista, formuleringen i ett
felmeddelande. Döp om `customer_name` till `name`, så slutar en partners integration att fungera vid
nästa förfrågan. Ändra genom tillägg i stället: lägg det nya fältet bredvid det gamla, markera det
gamla som utfasat, följ loggarna tills ingen läser det och ta bort det först i en ny huvudversion.

**En list-endpoint blir långsammare för varje månad.** Den returnerar varje matchande rad, vilket
gick bra med femtio poster vid lanseringen och ger timeout vid tvåhundratusen. Paginera från första
versionen, med en standardstorlek på sidan och ett hårt maximum som klienten inte kan gå över. För
stora eller livligt använda samlingar är en markör (cursor) bättre än en förskjutning (offset): med
en förskjutning puttar en rad som infogas mellan två förfrågningar en annan rad till nästa sida, där
klienten läser den två gånger.

```http
GET /v1/orders?limit=50&after=ord_8f2c HTTP/1.1
Host: api.example.com
```

**En kund läser en annan kunds order.** API:et kontrollerar att anroparen är inloggad och hämtar
sedan `/v1/orders/42` enbart utifrån identifieraren, så den som ändrar numret i adressen kan bläddra
genom andra människors data. Autentisering besvarade frågan om vem som anropar, men ingenting
frågade om just den anroparen äger order 42. Avgränsa varje uppslag efter ägare i själva
databasfrågan, och behåll ett test som loggar in som ett konto och begär ett annat kontos poster.

**Svaret bär kolumner som ingen tänkte publicera.** En endpoint serialiserar en rad ur databasen
eller ett ORM-objekt precis som det är, så att hashen av ett lösenord, en intern flagga eller en
leverantörs inköpspris går ut till varje klient, och en kolumn som läggs till nästa år publiceras
samma dag som den skapas. Samma misstag på indatasidan låter en förfrågan sätta `role` eller
`is_admin` bara genom att ta med fältet i kroppen. Ge varje endpoint uttryckliga typer för in- och
utdata som räknar upp de tillåtna fälten, så att publiceringen av ett fält blir ett beslut som någon
fattar.

## Läs mer

- [RFC 9110: HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110) — metoderna, statuskoderna och
  header-fälten som varje webb-API byggs av, så som IETF definierar dem.
- [RFC 9205: Building Protocols with HTTP](https://www.rfc-editor.org/rfc/rfc9205) — aktuell bästa
  praxis för att utforma en applikation ovanpå HTTP, bl.a. hur den kan utvecklas över tid.
- [RFC 9457: Problem Details for HTTP APIs](https://www.rfc-editor.org/rfc/rfc9457) — en
  standardiserad JSON-form för felsvar, så att klienter tolkar varje misslyckande på samma sätt.
- [RFC 6585: Additional HTTP Status Codes](https://www.rfc-editor.org/rfc/rfc6585) — där 429 Too
  Many Requests definieras, tillsammans med `Retry-After` som talar om för en begränsad klient när
  den kan försöka igen.
- [Semantic Versioning 2.0.0](https://semver.org/) — reglerna för att signalera en API-ändring som
  inte är bakåtkompatibel genom ett versionsnummer.

<https://engineer.company/sv/glossary/api/>
