JSON
JSON és un format de text que permet representar qualsevol estructura de dades.
Introducció
JSON es basa en una propietat fonamental dels llenguatges de programació: qualsevol estructura de dades es pot representar amb diccionaris i llistes de forma recursiva.
JSON permet convertir qualsevol estructura de dades a una representació de text simple.
D’aquesta manera, tant tu com qualsevol llenguatge de programació podeu llegir i escriure dades JSON.
Diccionari
El concepte de diccionari ve del diccionari físic, i és el terme que utilitza Python encara que en altres llenguatges té un altre nom.

A continuació tens un exemple molt senzill d’una representació JSON:
Es tracta d’un diccionari amb només una entrada, on "name" és la clau i "Eva" és el valor.
El nom és un string i ha d’anar envoltat de cometes dobles ""
TypeScript
TypeScript no inclou un tipus de dades natiu “diccionari” perquè els objectes en TypeScript es poden utilitzar com si fossin diccionaris si el tipus és any.
Per exemple, aquí tens un objecte JSON que representa una persona:
"name": "Eva",
"age": 30
}A continuació tens el mateix objecte representat com un objecte de TypeScript:
name: "Eva",
age: 30
}Cap diferència? 🤗
Fixa’t que l’única diferència és que JSON utilitza cometes dobles per a les claus!
I sempre has d’utilitzar cometes dobles per representar un string, mai pots utilitzar cometes simples: ‘Eva’ no és vàlid en JSON.
Instal·la Deno:
Crea un projecte nou amb el nom json:
mkdir json
cd json
deno init- Pots obrir el projecte amb PyCharm.
- Instal·la el plugin de Deno
JSON ens permet convertir una estructura a un string amb la funció JSON.stringify().
Crea un fitxer write.ts.
name: "Eva",
age: 30
}
jsonPots veure que per pantalla s’imprimeix un string: name i age van entre cometes dobles (""):
deno run write.ts{"name":"Eva","age":30}Un cop tenim el JSON convertit en string, el podem escriure en diversos destins, com una resposta d’API, un fitxer o qualsevol altra cosa.
Per exemple, escriu el string al fitxer eva.json:
name: "Eva",
age: 30,
};
;
"data", ;
"data/eva.json", json;Als exemples anteriors utilitzem JSON.stringify(eva, null, 2).
El 2 indica a Deno que utilitzi dos espais d’indentació, cosa que fa que el fitxer .json resultant sigui molt més fàcil de llegir per a les persones!
Com que estem escrivint un script senzill on el bloqueig no és cap problema, pots utilitzar la versió síncrona.
En Deno, els mètodes mkdir i mkdirSync inclouen una opció recursiva. Quan val true, es comporta com mkdir -p: crea el directori si no existeix (incloent-hi els directoris pare) i no llança cap error si el directori ja existeix.
Deno és segur per defecte. Per permetre que l’script escrigui al disc, l’has d’executar amb el flag --allow-write al terminal:
deno run --allow-write .\write.tsSi executes l’script pots veure que es crea un fitxer eva.json que tant tu com qualsevol llenguatge de programació podeu llegir sense problemes:
gc data/eva.json "name": "Eva",
"age": 30
}Python
Aquí tens l’objecte JSON que representa una persona:
"name": "Eva",
"age": 30
}A continuació tens el mateix objecte representat com un diccionari en Python:
: ,
: 30
}Cap diferència? 🤗
Inicia un projecte Python amb Uv dins de la carpeta del teu projecte:
uv initCrea l’script read.py:
=
=
Amb la funció loads pots llegir un str i convertir-lo en un diccionari Python.
uv run read.pyModifica el fitxer read.py per llegir el fitxer eva.json que ha creat l’script de TypeScript:
=
Pots veure que TypeScript i Python poden compartir dades 💞:
python.exe .\read.py
EvaEl problema és que poden compartir dades amb qualsevol llenguatge que passi per allà, fins i tot amb tu; no són un bon exemple de fidelitat, JSON és molt, molt simple 😒
Activitats
Aquí tens un objecte TypeScript que representa un llibre:
title: "The Art of Computer Programming",
author: "Donald Knuth"
}Modifica:
- L’script
write.tsperquè escrigui el llibre abook.json - L’script
read.pyperquè llegeixi el llibre i imprimeixi el títol.
Show solution
title: "The Art of Computer Programming",
author: "Donald Knuth"
}
"data/book.json", json
=
Funciona ! 😀
deno run --allow-write write.ts
uv run read.pyDonald KnuthLlegeix el fitxer deno.json amb Python i imprimeix per consola els imports de Deno:
Show solution
=
Llista
Una llista és un conjunt ordenat d’elements al qual es pot accedir per posició.
A continuació tens un exemple d’una llista:
Python
Aquí tens una llista en JSON:
I la mateixa llista en Python 🤗 :
Crea l’script write.py:
=
Amb la funció json.dump converteixes un objecte Python en un str JSON.
uv run write.pyTypeScript
Una llista “json” es representa amb un array de TypeScript: 🤗
Crea el fitxer read.ts per llegir les dades del fitxer list.json:
itemsuv run write.py
deno run --allow-read .\read.ts[ 1, "hello", false ]Activitat
Modifica el fitxer write.py:
= ,
,
]
Executa l’script per crear el fitxer data.json:
uv run write.pyModifica el fitxer read.ts perquè importi les dades de data.json i imprimeixi només els noms dels clients:
Show solution
Tipus
Tipus bàsics
JSON només té tres tipus bàsics: string, number i boolean!
string
Un string té aquestes propietats:
- Un string consisteix en zero o més caràcters Unicode entre cometes dobles (
""). - Un string entre cometes simples (
') no és vàlid – a diferència de TypeScript i Python.
A més, un string pot contenir els caràcters “backslash-escaped” següents:
\" | Cometa doble |
\\ | Barra invertida |
\/ | Barra |
\b | Retrocés |
\f | Salt de pàgina |
\n | Salt de línia |
\r | Retorn de carro |
\t | Tabulador |
\u | Seguit de quatre dígits hexadecimals |
number
"age": 29,
"cost": 299.99,
"temperature": -10.5,
"unitCost": 0.2,
"speedOfLight": 1.23e11,
"speedOfLight2": 1.23e+11,
"avogadro": 6.023E23,
"avogadro2": 6.023E+23,
"oneHundredth": 10e-3,
"oneTenth": 10E-2
}Els nombres segueixen el format de coma flotant de doble precisió de TypeScript i tenen les propietats següents:
- Els nombres sempre estan en base 10 (només es permeten els dígits del 0 al 9) sense zeros inicials.
- Els nombres poden tenir una part fraccionària que comença amb un punt decimal (.).
- Els nombres poden tenir un exponent de 10, que es representa amb la notació
eoEamb un signe positiu o negatiu per indicar una exponenciació positiva o negativa. - No s’admeten els formats octal i hexadecimal.
- A diferència de TypeScript, els nombres no poden tenir un valor de
NaN(no és un nombre, per a nombres no vàlids) oInfinity.
boolean
"isRegistered": true,
"emailValidated": false
}Els booleans tenen les propietats següents:
- Els booleans només poden tenir un valor de
trueofalse. - El valor
trueofalsea la dreta dels dos punts (:) no va envoltat de cometes.
null
Encara que tècnicament no sigui un tipus de valor, null és un valor especial en JSON.
"address": "line1": "555 Any Street",
"line2": null,
"city": "Denver",
"stateOrProvince": "CO",
"zipOrPostalCode": "80202",
"country": "USA"
}
}Els valors nuls tenen les característiques següents:
- No van envoltats de cometes
- Indiquen que una clau/propietat no té valor
- Actuen com a marcador de posició
“Tipus” derivats
JSON només té tres tipus bàsics perquè amb un string pots representar qualsevol tipus de dades.
Només cal que tots ens posem d’acord en com representem una dada.
En aquest enllaç tens la guia d’estil de Google respecte a JSON: JSON Style Guide.
Data
Per exemple, Google prefereix que les dates segueixin el format RFC 3339:
"date": "2014-03-01T23:46:11-05:00"
}La data anterior proporciona un desplaçament respecte a l’hora universal coordinada (UTC) (des d’UTC/GMT — Hora mitjana de Greenwich) de -5 hores, que és l’hora estàndard de l’est dels EUA. Tingues en compte que l’RFC 3339 és un perfil de la ISO 8601.
// Format RFC 3339
// 2025-02-17T22:20:57.141ZLa diferència principal és que la ISO 8601 de l’Organització Internacional d’Estandardització permet substituir la T (que separa la data i l’hora) per un espai, i l’RFC 3339 no ho permet.
Valors de latitud/longitud
Les API geogràfiques (p. ex., Google Maps) i les API relacionades amb un sistema d’informació geogràfica (SIG) utilitzen dades de latitud/longitud. Per garantir la coherència, Google recomana que les dades de latitud/longitud segueixin l’estàndard ISO 6709.
Segons Google Maps, les coordenades de l’Empire State Building a la ciutat de Nova York són 40,748747° N, 73,985547° O i es representarien en JSON..
"empireStateBuilding": "40.748747-73.985547"
}Aquest exemple segueix el format ±DD.DDDD±DDD.DDDD, amb les convencions següents:
- La latitud va primer.
- La latitud nord (de l’equador) és positiva.
- La longitud est (del primer meridià) és positiva.
- La latitud/longitud es representa amb un string. No pot ser un nombre a causa del signe menys.
Estructures complexes
Combinant diccionaris i llistes, i amb només tres tipus bàsics, pots representar qualsevol tipus de dades:
,
,
}
]A continuació tens el diagrama de classes corresponent:
Referències repetides
Quan transformem una estructura de dades en un text JSON, el procés no codifica referències, sinó que va codificant els objectes que troba al seu pas.
Per exemple, en un projecte l’owner i el mantainer són del tipus User:
A continuació tens un exemple en què, al projecte “Quantum System”, owner i mantainer fan referència al mateix objecte de tipus User:
;
;
;
name: "Quantum System",
owner: david,
mantainer: david,
};
project, null, 2;Si executes el codi, pots veure que l’owner i el mantainer es codifiquen com si fossin dos objectes diferents.
deno run project.ts
{"name":"Quantum System","owner":{"name":"David"},"mantainer":{"name":"David"}}Això significa que hi pot haver dades repetides perquè un objecte pot fer referència al mateix objecte de forma directa o indirecta.
Al nostre exemple, si desem el projecte en un fitxer i el tornem a llegir, tindrem un projecte en què l’owner i el mantainer són dos objectes diferents encara que tinguin el mateix nom:
;
;
;
name: "Quantum System",
owner: david,
mantainer: david,
};
"data/project.json", project;
project = "data/project.json";
project.owner == project.mantainer;
project.owner.name = "Eva";
project.mantainer.name; // EvaSi executes l’script, pots veure que si canvio el nom de l’owner, el nom del mantainer no canvia perquè són dos objectes diferents:
deno run -A project.tsfalse
DavidHas d’evitar un codi d’aquest tipus si vols compartir aquestes dades amb JSON 💩 !
No hi ha referències, hi ha redundància!
Deno també ofereix un flag --allow-all que concedeix tots els permisos a l’script. Això desactiva completament el sandbox de seguretat, i s’ha d’utilitzar amb precaució.
deno run -A script.ts
deno run --allow-all script.tsReferències circulars
Com ja s’ha explicat abans, la serialització no té en compte si un objecte ja s’havia serialitzat.
Això significa que, a més de la redundància, la serialització només funciona amb arbres: un objecte arrel, ramificacions i tot acaba en fulles.
Es comença amb un objecte i es van processant de forma recursiva totes les propietats que són referències fins que no queda cap objecte referenciat per processar.
Per exemple, si David té una referència directa o indirecta amb Esther, i Esther té una referència directa o indirecta amb David …
la recursió no acabarà mai 💫💫💫💫💫 …
;
;
;
david.couple = esther;
"data/david.json", david;però JSON no ho permet 😱 … no creu en l’amor etern 💞 …
deno run -A couple.tserror: Uncaught (in promise) TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'couple' -> object with constructor 'Object'
--- property 'couple' closes the circle
Deno.writeTextFileSync("data/david.json", JSON.stringify(david));Deno t’informa exactament del problema Converting circular structure to JSON i d’on es troba la referència circular property ‘couple’ closes the circle.
què pot fer el pobre gatet 🙀🙀 ??
Canviar el disseny 😼 … i no posar data de finalització (sempre optimista, pensar que les parelles són per sempre 💞) …
I ja podem escriure el codi:
;
;
;
;
start: "Un noche de lluvía con luna en el cielo",
one: david,
two: esther,
};
"data/couple.json", couple, null, 2;I JSON diu que sí 😀, a més és més romàntic 🌹:
deno run -A couple.ts
gc data/couple.json "start": "Un noche de lluvía con luna en el cielo",
"one": "name": "David"
},
"two": "name": "Esther"
}
}Que la data hagi d’estar en format RFC 3339 és un estil de Google … el start d’aquest codi també és una data “tipus” string 🌈.
Però hi ha un problema: una parella és cosa de dos, one i two, que no és el mateix que first i second encara que alguns ho interpretaran així, i el he i she fa temps que no s’admet com a exclusiu …
La propera vegada dissenyem un zoo 😒: 🐯 🦒 🐮 🐰 🦓 🐼 🐨 🐑 🦛 🦏 🦬 🐆
Activitat - Vuelos Pájaro Bobo
L’empresa “Vuelos Pájaro Bobo” és una start-up que necessita un sistema bàsic de gestió de vols.
A continuació tens el disseny de l’estructura de dades:
De moment només té vols des de “Barcelona”, codi BCN, i sí, els passatgers s’identifiquen pel nom.
Per tant, si en un vol ja hi ha una passatgera que es diu “Eva” i una altra “Eva” vol viatjar, o es canvia el nom o no pot viatjar en aquest vol 👏.
A continuació tens un exemple per al vol bcn-cdg-tomorrow-morning-after-breakfast.json:
"id": "bcn-cdg-tomorrow-morning-after-breakfast",
"ufoSeen": false,
"plane": "name": "fearless-ostrich",
"seats": 50
},
"departure": "code": "BCN",
"name": "Aeroport Josep Tarradellas Barcelona",
"city": "Barcelona",
"country": "Spain"
},
"arrival": "code": "CDG",
"name": "Paris-Charles de Gaulle",
"city": "Paris",
"country": "France"
},
"passengers": ,
,
,
,
]
}Has de completar l’script bobo.ts perquè permeti afegir passatgers:
"Welcome to Vuelos Pájaro Bobo"
// 👉 el teu torn! En acabar has de crear un binari executable:
deno compile bobo.tsAquest binari es pot executar directament en qualsevol sistema Windows:
.\bobo.exeWelcome to Vuelos Pájaro BoboActivitat
Fes els mateixos exercicis en Python