# GraphQL

## Vad det är

GraphQL är ett frågespråk för API:er tillsammans med den körmiljö som utför
frågorna på servern. Klienten skickar ett dokument som namnger exakt de fält den
vill ha, och servern svarar med data i samma form. Specifikationen beskriver det
som ett språk och en exekveringsmotor för klient-server-program. Den anger att
GraphQL skapades 2012, att arbetet med det som öppen standard inleddes 2015 och
att det sedan 2019 är en leverans från GraphQL Specification Project under Joint
Development Foundation. Den senaste utgåvan är från september 2025.

Allt utgår från det schema som en tjänst publicerar: en uppsättning typer, var
och en med namngivna fält, och varje fält med en egen typ. De inbyggda
skalärtyperna är `Int`, `Float`, `String`, `Boolean` och `ID`, och en tjänst kan
lägga till egna skalärer, till exempel en för UUID:er. Varje typ får vara null
om den inte är märkt med `!`, så en `String!` kan aldrig vara null, och listor
skrivs inom hakparenteser: `[LineItem!]!` är en lista som alltid finns och
aldrig innehåller null. Även själva schemat går att ställa frågor till. Genom
introspektionsfälten `__schema` och `__type` kan en klient fråga en tjänst vad
den erbjuder, och utvecklarverktyg och klientbibliotek bygger just på det.

Det finns tre sorters operationer. En `query` är med specifikationens ord ”a
read-only fetch”, alltså en hämtning som bara läser; en `mutation` är en
skrivning följd av en hämtning; och en `subscription` är en långlivad förfrågan
som levererar data som svar på en följd av händelser över tid. På servern står
en funktion bakom varje fält, oftast kallad en resolver, och den tar fram
fältets värde. Tjänsten validerar först en operation mot schemat och anropar
först därefter resolverfunktionerna för de fält som operationen har valt.
Toppnivåfälten i en `mutation` körs ett i taget i stället för parallellt, så att
två skrivningar i samma förfrågan inte kan krocka med varandra.

Specifikationen föreskriver varken transport eller serialiseringsformat. HTTP är
det vanligaste valet, och där ligger ett GraphQL-API på en enda URL, oftast med
ändelsen `/graphql`, och svarar i JSON, det vanligaste formatet. Klienten
skickar en POST vars JSON-kropp innehåller `query`-texten och vid behov dess
`variables`. En server får också ta emot GET för `query`-operationer, men en
`mutation` måste alltid skickas som POST. Svaret har resultatet under `data` och
allt som gick fel under `errors`. GraphQL Foundations vägledning om allt detta
följer en GraphQL-over-HTTP-specifikation som fortfarande är ett utkast.

## Varför det spelar roll

I de flesta HTTP-API:er är det servern som bestämmer vad varje slutpunkt
returnerar. En skärm som behöver en orders status och kundens namn får antingen
hela ordern och hela kunden, alltså mer än den bad om, eller måste skicka en
förfrågan per resurs och själv foga ihop svaren. Specifikationen kallar de två
problemen over-fetching och under-fetching. GraphQL vänder på det: klienten
frågar på nivån av enskilda fält och får exakt de fälten tillbaka, varken mer
eller mindre. En förfrågan kan också följa relationer, från en order till dess
orderrader och vidare till kunden, eftersom förfrågan har samma form som de data
den får tillbaka.

Typsystemet lönar sig två gånger. Varje operation valideras mot schemat innan
någon resolver körs, så ett felstavat fält eller ett argument av fel typ avvisas
i sin helhet innan något alls har utförts, och verktyg kan fånga samma misstag
medan koden fortfarande skrivs. Och eftersom en klient bara får de fält den har
valt kostar ett nytt fält ingenting för befintliga klienter. Det gör det
praktiskt att vidareutveckla ett API utan versionsnummer: ett nytt fält dyker
upp bredvid det gamla, det gamla märks med `@deprecated` och en motivering, det
förblir giltigt så att befintliga klienter inte går sönder, och det tas bort när
ingen klient använder det längre.

Kostnaderna är verkliga, och de flesta kommer av att man kliver utanför det
maskineri som HTTP själv har. Entiteter identifieras inte längre av URL:er, och
allt går till en enda adress, oftast med POST, medan det är GET-förfrågningar
som i regel räknas som cachebara som standard. Den cachning som ett REST-API får
gratis från mellanleden måste byggas upp igen med avsikt. Statuskoden berättar
inte längre hela historien, för ett svar med både data och fel är fortfarande en
framgång på HTTP-nivå. Klienten sätter nu ihop förfrågningar som servern aldrig
har sett, så en enda förfrågan kan begära mycket arbete, och att skydda servern
mot det är tjänstens uppgift, inte något GraphQL gör åt den. Resolverfunktioner
per fält är lätta att skriva, men skrivna naivt blir de mycket pratsamma mot
databasen bakom dem.

## Så ser det ut i praktiken

En liten del av ett schema för ordrar, var och en med orderrader och en kund:

```graphql
type Query {
  order(id: ID!): Order
}

type Order {
  id: ID!
  status: String!
  items: [LineItem!]!
  customer: Customer
}

type LineItem {
  name: String!
  quantity: Int!
}

type Customer {
  name: String!
}
```

En skärm som visar status, orderraderna och kundens namn skickar den här
operationen till `/graphql` i kroppen på en POST, med `{"id": "7421"}` som
variabler:

```graphql
query OrderSummary($id: ID!) {
  order(id: $id) {
    status
    items {
      name
      quantity
    }
    customer {
      name
    }
  }
}
```

Anta att ordern och dess rader hämtas men att tjänsten bakom `customer` ligger
nere. Svaret innehåller ändå allt som gick att ta fram. Fältet som misslyckades
kommer tillbaka som null, och en post i `errors` talar om vad som gick fel, var
i dokumentet det hände (rad 8, kolumn 5 är `customer`) och vilken sökväg i
svaret det gäller:

```json
{
  "data": {
    "order": {
      "status": "open",
      "items": [{ "name": "notebook", "quantity": 2 }],
      "customer": null
    }
  },
  "errors": [
    {
      "message": "Customer service unavailable",
      "locations": [{ "line": 8, "column": 5 }],
      "path": ["order", "customer"]
    }
  ]
}
```

Eftersom `customer` är deklarerat så att det får vara null stannar skadan vid
det fältet. Hade det varit `Customer!` hade felet fortplantat sig upp till
föräldern, och hela ordern hade kommit tillbaka som null. Och eftersom `data`
inte är null svarar servern med en 2xx-status trots att det finns ett fel: HTTP
har ingen statuskod för delvis framgång. En klient som bara tittar på
statuskoden kommer att behandla svaret som komplett.

Den motsatta designen, där servern äger formen på varje svar, är den som ett
projekt i portföljen här på webbplatsen byggde: en
[JSON-väg rakt från Postgres till API:et](/sv/portfolio/designed-a-json-passthrough-from-postgres-to-api/).
Där sätter PostgreSQL-funktioner ihop hela svaret som JSON, och Go-handlern
vidarebefordrar det orört, så när man ändrar vad en funktion returnerar ändras
också det klienten tar emot, utan att någon ändrar en enda rad handlerkod.
Frontenden är där direkt beroende av den form som databasen ger den. I GraphQL
är det klienten som namnger fälten, och servern måste vara redo att leverera
vilken kombination av dem som helst som schemat tillåter.

## Var det går fel

**Ett fält, tusen databasanrop.** Varje resolver är en liten funktion, en per
fält, och en naiv tjänst anropar dem ett objekt i taget. En lista med ordrar och
varje orders kund kostar då ett databasanrop för listan och ett till för varje
order i den. GraphQL Foundations vägledning kallar det N+1-problemet och pekar
på batchning: de uppslag som begärs inom ett kort tidsfönster samlas ihop och
skickas till databasen som en enda förfrågan, med ett verktyg som Facebooks
DataLoader.

**En förfrågan begär allt.** Eftersom det är klienten som skriver operationen
kan ett dokument nästla vänners vänner många nivåer ner, upprepa ett dyrt fält
under hundra alias eller packa in många operationer i en enda förfrågan. Var och
en är giltig GraphQL, och var och en kan binda upp servern. Försvaret ligger hos
tjänsten: paginera listfält, avvisa operationer som överskrider ett största djup
eller en största bredd innan exekveringen börjar, sätt tak för alias och
batchstorlek, och ge för finare kontroll fälten vikter och avvisa varje
operation vars uppskattade kostnad går över budget, en teknik som kallas query
complexity analysis och som specifikationen själv inte ger några regler för. Ett
API som bara betjänar sina egna klienter kan gå längre med trusted documents, så
att bara operationer som har sparats i förväg och slås upp via hash får köras
över huvud taget.

**200 OK döljer felet.** Ett svar med fel kan ändå vara en 2xx, som i exemplet
ovan. Med den äldre medietypen `application/json` går vägledningen längre: en
2xx rekommenderas även när en giltig förfrågan inte kan utföras, och vissa äldre
servrar returnerar 2xx även vid valideringsfel. En klient, och övervakningen
runt den, måste läsa `errors` och inte bara statuskoden. Den nyare medietypen
`application/graphql-response+json` ger statuskoden mening igen, eftersom en
giltig förfrågan som inte kan utföras då får en 4xx eller 5xx, och klienter bör
be om den i sitt `Accept`-huvud.

**Cachningen slutar fungera.** Varje operation är en POST till samma URL, så
cacharna mellan klient och server, ett CDN inräknat, ser en enda adress och en
metod som de inte cachar som standard. Det hjälper att skicka
`query`-operationer som GET, men ett långt dokument kan överskrida den URL-längd
som webbläsare och CDN:er accepterar. Persisted queries löser båda problemen:
klienten skickar en hash, och servern slår upp hela dokumentet innan det
valideras och utförs. Överallt där svar cachas över HTTP måste känsliga svar
cachas privat eller inte alls.

**Ett fält försvinner.** Klienter väljer fält ett och ett, så om ett fält tas
bort eller byter namn går varje klient som fortfarande väljer det sönder, och
inte på något skonsamt sätt: en operation som nämner ett okänt fält underkänns i
valideringen i sin helhet och ger inga data alls. Specifikationen håller
utfasade fält giltiga just för att befintliga klienter inte ska gå sönder. Lägg
till ersättningen först, märk det gamla fältet med `@deprecated` och en
motivering som pekar på det nya, och ta bort det gamla fältet först när
ingenting längre väljer det.

## Läs mer

- [GraphQL Specification Versions](https://spec.graphql.org/) — alla utgåvor av
  specifikationen, från juli 2015 till utgåvan från september 2025, plus
  arbetsutkastet: språket, typsystemet, validering, exekvering och fel.
- [Serving over HTTP](https://graphql.org/learn/serving-over-http/) — den enda
  slutpunkten, POST och GET, de två medietyperna för svar och reglerna för
  statuskoder för var och en av dem.
- [Performance](https://graphql.org/learn/performance/) — GET för
  `query`-operationer, persisted queries, N+1-problemet och batchning.
- [Security](https://graphql.org/learn/security/) — trusted documents, gränser
  för djup, bredd och batcher, query complexity analysis samt introspektion och
  feldetaljer i produktion.

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