Udviklere

Hvad er JSON? Syntaksregler og ret på almindelige fejl

8 min læsning

JSON (JavaScript Object Notation) er et tekstformat, der repræsenterer struktureret data som nøgle-værdi-par og ordnede lister, opbygget af kun seks værdityper. Det er formatet, næsten alle web-API’er bruger til at sende og modtage data, og det dukker også op i konfigurationsfiler, logfiler og NoSQL-databaser. I modsætning til et JavaScript-objektliteral, som det ligner på overfladen, har JSON et lille og strengt regelsæt, og bryder du bare én af reglerne, bliver hele dokumentet umuligt at parse.

Hvad JSON egentlig er

Ethvert JSON-dokument er bygget af præcis seks værdityper:

  • String, kun i dobbelte anførselstegn, som "hej"
  • Tal, som 42 eller 3.14
  • Boolean, enten true eller false
  • null
  • Objekt, en uordnet samling af nøgle-værdi-par pakket ind i {}
  • Array, en ordnet liste af værdier pakket ind i []

Det er hele typesystemet. Der findes ingen datotype, intet undefined, ingen funktionstype, ikke noget andet. Objekter og arrays kan indlejres i hinanden så dybt, som du har brug for, men enhver værdi på ethvert niveau skal være en af de seks typer.

Syntaksreglerne, der følger med de typer, er lige så faste:

  • Objektnøgler skal være strenge i dobbelte anførselstegn. `{"navn":"Ada"}` er gyldigt, `{navn:"Ada"}` er det ikke.
  • Intet komma efter det sidste element. Den sidste egenskab i et objekt og det sidste element i et array må ikke have et komma efter sig.
  • Ingen kommentarer af nogen art, hverken // eller /* */.
  • Strenge og nøgler bruger udelukkende dobbelte anførselstegn. Enkelte anførselstegn er gyldig JavaScript, men ikke gyldig JSON.
  • Nøgler kan aldrig stå uden anførselstegn, uanset hvor simpelt navnet er.
  • NaN, Infinity og undefined er ikke gyldige JSON-værdier, selvom alle tre virker fint i JavaScript.
  • Funktioner kan ikke repræsenteres i JSON. Der er ingen måde at serialisere adfærd på, kun data.

Bryd bare én af disse regler, og en JSON-parser stopper og melder en fejl i stedet for at gætte, hvad du mente.

JSON versus et JavaScript-objektliteral

JSONs {}- og []-syntaks er lånt direkte fra JavaScripts objekt- og array-litteraler, og det er netop derfor, de to bliver forvekslet. De ligner næsten hinanden til forveksling på skærmen, men et JavaScript-objektliteral er mere tilgivende på hvert eneste punkt, hvor JSON er strengt:

EgenskabJSONJavaScript-objektliteral
Nøgler skal have anførselstegnJa, kun dobbelteNej, valgfrit
Komma efter sidste element tilladtNejJa
Kommentarer tilladtNejJa
Strenge i enkelte anførselstegnNejJa
Funktioner som værdierNejJa
undefined som værdiNejJa

Det er her, en stor del af debugtiden går tabt. Kopierer du et objektliteral direkte ud af en JavaScript-fil, med uquotede nøgler, komma efter sidste element og det hele, ind et sted, der forventer JSON, får du noget, der kører upåklageligt som JavaScript, men fejler i samme øjeblik JSON.parse rører ved det. JSON er ikke en delmængde af JavaScript-syntaks, du kan skrive løst, det er et selvstændigt, strengere format, der bare deler tegnsætning med et andet.

Praktisk eksempel: minificering og formatering af et rigtigt API-svar

Tag et typisk brugerobjekt, som en API kunne returnere:

{
  "id": 1,
  "name": "Ada Lovelace",
  "email": "[email protected]",
  "roles": [
    "admin",
    "user"
  ],
  "active": true,
  "meta": null
}

Den pænt formaterede version, med 2-mellemrums indrykning, fylder 145 tegn. Den samme data minificeret, hvor hvert mellemrum og linjeskift er fjernet, ser sådan ud:

{"id":1,"name":"Ada Lovelace","email":"[email protected]","roles":["admin","user"],"active":true,"meta":null}

Det er 107 tegn, cirka 35 % mindre, og hele forskellen er ren whitespace. Ikke en eneste værdi eller nøgle har ændret sig, dataen er identisk.

Det er derfor API’er sender JSON minificeret over ledningen: i stor skala løber de 35 % sparede bytes op i reel gevinst på båndbredde og latenstid på tværs af millioner af requests, og ingen klientkode har brug for indrykningen for at parse værdien korrekt. Men den samme minificerede streng er nærmest ulæselig for et menneske. Skal du debugge et svar og se indlejringen, nøglenavnene og hvor et array starter og slutter, formaterer du den tilbage til den indrykkede version. Samme data, to forskellige formål: ét til maskiner, ét til dig.

Formatér din egen JSON

Indsæt minificeret eller rodet JSON herunder for at se det formateret med korrekt indrykning, eller brug værktøjet den anden vej for at minificere et formateret dokument, før du sender det et sted hen, hvor størrelsen betyder noget.

JSON-formatering og validering
Gratis, ingen tilmelding, virker på alle enheder.
Åbn hele værktøjet

Almindelige fejl og specialtilfælde

Komma efter det sidste element. Givet `{"id":1,"name":"Ada",}`, melder V8 (motoren bag Chrome og Node.js):

Expected double-quoted property name in JSON at position 21 (line 1 column 22)

Kommaet efter "Ada" har intet efter sig, og JSON har ikke noget begreb om et valgfrit afsluttende separator. Firefox’ SpiderMonkey-motor formulerer sine fejl anderledes, men parsingen fejler på samme måde i enhver JSON-konform motor.

Uquotede nøgler. `{id:1}` fejler med:

Expected property name or '}' in JSON at position 1 (line 1 column 2)

Parseren forventer en streng i dobbelte anførselstegn lige efter { og finder i stedet et bart identifikatornavn.

Nøgler i enkelte anførselstegn. `{'a':1}` rammer samme fejlklasse:

Expected property name or '}' in JSON at position 1 (line 1 column 2)

Enkelte anførselstegn er ikke en gyldig måde at åbne en streng på i JSON, så parseren behandler 'a' præcis som den ville behandle en uquotet nøgle: ikke et gyldigt egenskabsnavn.

NaN og undefined som værdier. `{"a":NaN}` giver:

Unexpected token 'N', "{"a":NaN}" is not valid JSON

Og `{"a":undefined}` giver:

Unexpected token 'u', "{"a":undefined}" is not valid JSON

Begge dele er lovlige i et JavaScript-objektliteral, men har ingen repræsentation i JSON. Kan en værdi i din applikation være NaN eller undefined, skal du konvertere den til null eller en streng, før du serialiserer.

Ens nøgler overskriver hinanden i stilhed. `{"a":1,"a":2}` er syntaktisk gyldig JSON, helt uden fejl, og parses til `{"a":2}`. De fleste parsere, inklusive JavaScripts egen, beholder kun den sidste forekomst af en gentaget nøgle og kasserer den tidligere uden varsel. Det er en snigende kilde til rigtige bugs: et build-værktøj, der sammensætter konfigurationsfragmenter, eller en manuelt redigeret fil, hvor nogen ved en fejl indsætter en blok to gange, kan ende med samme nøgle to gange, og fordi der ikke kommer nogen fejl, opdager ingen det, før den forkerte værdi dukker op et sted længere nede i kæden.

Ofte stillede spørgsmål

Hvad er JSON? Det er et tekstformat til struktureret data, bygget af seks værdityper: strenge, tal, booleans, null, objekter og arrays. Det er det mest almindelige format til API-forespørgsler og -svar, og det bruges også i konfigurationsfiler og mange databaser.

Er JSON det samme som et JavaScript-objekt? Nej. JSON ligner et JavaScript-objektliteral, men er strengere: nøgler skal stå i dobbelte anførselstegn, komma efter sidste element er ikke tilladt, kommentarer er ikke tilladt, og værdier som undefined eller en funktion kan slet ikke repræsenteres. Et JavaScript-objektliteral tillader alt det, JSON tillader intet af det.

Hvorfor ødelægger et ekstra komma mit JSON? Fordi JSONs grammatik ikke har nogen regel for et ekstra komma efter det sidste element i et objekt eller array. En parser, der læser `{"id":1,"name":"Ada",}`, forventer endnu et egenskabsnavn efter kommaet og finder i stedet den lukkende klamme, hvilket er præcis, hvad fejlen “Expected double-quoted property name in JSON” melder.

Understøtter JSON kommentarer? Nej. Der findes ingen syntaks for // eller /* */ noget sted i JSON-specifikationen. Har du brug for at kommentere en JSON-fil til mennesker, er de gængse løsninger en separat dokumentationsfil, en ekstra "_comment"-nøgle behandlet som almindelig data, eller at skifte til et format, der understøtter kommentarer, som JSON5 eller YAML.

Hvad er forskellen mellem at formatere og minificere JSON? Formatering (også kaldet beautifying eller prettifying) tilføjer indrykning og linjeskift, så et menneske kan læse strukturen med det samme. Minificering fjerner al den whitespace igen for at give den kortest mulige streng. Begge repræsenterer nøjagtig den samme data, forskellen er rent visuel, og det er almindeligt at konvertere mellem de to, alt efter om JSON’en skal læses af en person eller sendes over et netværk.

Bliver mine data sendt til en server, når jeg bruger en online JSON-formaterer? Med pluri.tools’ JSON-formaterer, nej. Formatering, minificering og validering kører udelukkende med JSON.parse og JSON.stringify i din browsers JavaScript-motor. Der er ikke noget fetch- eller netværkskald involveret, så den JSON, du indsætter, forlader aldrig din enhed.

JSON-formatering og validering
Prøv det nu selv med hele værktøjet.
Prøv nu