,

Bygg ditt eget sakssystem-API: fire ting jeg skulle visst først

Bygg ditt eget sakssystem-API: fire ting jeg skulle visst først

Vi bygde et sakssystem med REST-API til internt bruk. Kunder, prosjekter og saker henger sammen, og fire valg vi tok tidlig i løpet endte med å spare oss for en god del omskriving lenger ut. Her er de, uten pynt.

1. Nest ressursene i URL-en

Skjematisk diagram over nestede API-ressurser: kunde inneholder prosjekt som inneholder sak, med tilhørende URL-sti

En sak tilhører et prosjekt, og et prosjekt tilhører en kunde. Speil det hierarkiet i ruten. Flate ruter som /issues/42 blir tvetydige i det øyeblikket du har mer enn ett prosjekt: hvem eier saken, og hvor hører den hjemme. Nestede ruter gjør eierskapet eksplisitt, og de lar deg autorisere på hvert nivå i stedet for å ettersjekke i etterkant.

GET  /customers/{customer}/projects/{project}/issues
POST /customers/{customer}/projects/{project}/issues
GET  /customers/{customer}/projects/{project}/issues/{issue}

Prisen er lengre URL-er. Det er verdt det. Du slipper å gjette kontekst ut av query-parametere, og ruteren gir deg en 404 gratis den dagen en sak ikke tilhører prosjektet i URL-en.

2. Skill det brukervennlige nummeret fra database-id-en

Brukeren vil ha et lite, lesbart saksnummer per prosjekt. Prosjekt A har sak 1, 2, 3. Prosjekt B har også sak 1, 2, 3. Fint for mennesker, men issue_number er altså ikke unikt på tvers av prosjekter. Bruk databasens id internt i URL-en, og vis issue_number i grensesnittet.

{
  "id": 4821,          // globalt unik, brukes i URL
  "issue_number": 3,   // vises til brukeren, unik per prosjekt
  "title": "Feil i eksport"
}

Blander du de to, kolliderer numrene på tvers av prosjekter, og du ender med oppslag som treffer feil sak. Hold dem adskilt fra dag én, så slipper du å nøste opp i det senere.

3. Tving JSON på skrivende kall

Flytskjema for API-forespørsel: klient sender header som tvinger JSON, server svarer med strukturert JSON i stedet for HTML-feilside

Feiler en forespørsel og klienten ikke uttrykkelig ba om JSON, svarer rammeverket gjerne med en pen HTML-feilside. API-klienten sitter da igjen med en haug markup i stedet for en strukturert feil den kan lese. Krev riktige headere på alle POST-, PUT- og DELETE-kall.

Accept: application/json
Content-Type: application/json

Med Accept: application/json tvinger du rammeverket til å svare JSON også ved valideringsfeil og 500. Det gjør klientkoden forutsigbar. Uten den bruker du gjerne en time på å lure på hvorfor parseren kveler på det som skulle vært et pent feilobjekt.

4. Enkle query-filtre slår smarte

Det er fristende å bygge et rikt filterspråk med nestede parametere. La være til du faktisk trenger det. Flate filtre er lette å lese, lette å dokumentere og lette å cache.

GET /customers/1/projects/2/issues?status=open
GET /customers/1/projects/2/issues?status=open&priority=high

Styr unna ?filter[status]=open. Det ser fancy ut, men koster mer i parsing, dokumentasjon og klientkode enn det gir tilbake i et internt system.

Svarformat

Hold svaret forutsigbart. En data-liste og en meta-blokk med paginering. Da slipper klienten å lete etter hvor nyttelasten ligger.

{
  "data": [ { "id": 4821, "issue_number": 3, "title": "..." } ],
  "meta": { "current_page": 1, "last_page": 5, "per_page": 20, "total": 92 }
}

Fire valg, tatt først, som ikke måtte gjøres om siden. Nest ressursene, skill visningsnummer fra id, tving JSON, hold filtrene flate. Ingen av dem er spesielt smarte. Alle fire er billige å innføre og dyre å rette opp i ettertid.


Trenger du hjelp med dette?

Ta kontakt for en uforpliktende prat om hvordan jeg kan hjelpe deg.

Navn