Artículo original escrito por: Kris Koishigawa
Artículo original: JSON Stringify Example – How to Parse a JSON Object with JS
Traducido y adaptado por: Keiler Guardo Herrera

JSON, o JavaScript Object Notation, está por todas partes. Si alguna vez has utilizado una aplicación web, es muy probable que hayas hecho uso de JSON para estructurar, almacenar y transmitir datos entre sus servidores y tu dispositivo.

En este artículo, repasaremos brevemente las diferencias entre JSON y JavaScript, y luego pasaremos a las diferentes formas de analizar JSON con JavaScript en el navegador y en los proyectos de Node.js.

Diferencias entre JSON y JavaScript

Aunque JSON se parece a un JavaScript común, es mejor pensar en JSON como un formato de datos, similar a un archivo de texto. Sucede que JSON se inspira en la sintaxis de JavaScript, y por eso se parecen tanto.

Veamos los objetos JSON y los arreglos JSON y comparémoslos con sus homólogos de JavaScript.

Objetos JSON frente a objetos literales de JavaScript

En primer lugar, aquí hay un objeto JSON:

{
  "nombre": "Jane Doe",
  "juego-favorito": "Stardew Valley",
  "suscriptor": false
}
perfil-jane.json

La principal diferencia entre un objeto JSON y un objeto JavaScript normal -también llamado objeto literal - se reduce a las comillas. Todas las claves y valores de tipo cadena de un objeto JSON tienen que ir entre comillas dobles (").

Los objetos literales de JavaScript son un poco más flexibles. Con los objetos literales, no es necesario encerrar las claves y las cadenas entre comillas dobles. En su lugar, puedes utilizar comillas simples ('), o no utilizar ningún tipo de comillas para las claves.

Este es el aspecto del código anterior como un objeto literal de JavaScript:

const perfil = {
  nombre: 'Jane Doe',
  'juego-favorito': 'Stardew Valley',
  suscriptor: false
}

Ten en cuenta que la clave 'favorite-game' va entre comillas simples. En el caso de los objetos literales, tendrás que encerrar entre comillas las palabras separadas por guiones (-).

Si quieres evitar las comillas, puedes reescribir la clave para usar camel case (juegoFavorito) o separar las palabras con un guion bajo (juego_favorito) en su lugar.

Arreglos JSON vs. Arreglos JavaScript

Los arreglos JSON funcionan prácticamente igual que los arreglos en JavaScript, y pueden contener cadenas, booleanos, números y otros objetos JSON. Por ejemplo:

[
  {
    "nombre": "Jane Doe",
    "juego-favorito": "Stardew Valley",
    "suscriptor": false
  },
  {
    "nombre": "John Doe",
    "juego-favorito": "Dragon Quest XI",
    "suscriptor": true
  }
]
perfiles.json

Esto es lo que se podrías ver en JavaScript:

const perfiles = [
  {
    nombre: 'Jane Doe',
    'juego-favorito': 'Stardew Valley',
    suscriptor: false
  },
  {
    nombre: 'John Doe',
    'juego-favorito': 'Dragon Quest XI',
    suscriptor: true
  }
];

JSON como cadena

Tal vez te preguntes, si hay objetos JSON y arreglos, ¿no podrías usarlo en tu programa como un objeto literal de JavaScript normal o un arreglo?

La razón por la que no se puede hacer esto es que JSON es realmente una cadena.

Por ejemplo, cuando se escribe JSON en un archivo separado como con perfil-jane.json o perfiles.json, ese archivo en realidad contiene texto en forma de un objeto o arreglo JSON, que resulta ser como JavaScript.

Y si haces una petición a una API, te retornará algo así:

{"nombre":"Jane Doe","juego-favorito":"Stardew Valley","suscriptor":false}

Al igual que con los archivos de texto, si quieres usar JSON en tu proyecto, tendrás que analizarlo o cambiarlo a algo que tu lenguaje de programación pueda entender. Por ejemplo, el análisis de un objeto JSON en Python creará un diccionario.

Una vez entendido esto, veamos diferentes formas de analizar JSON en JavaScript.

Cómo analizar JSON en el navegador

Si estás trabajando con JSON en el navegador, probablemente estés recibiendo o enviando datos a través de una API.

Veamos un par de ejemplos.

Cómo analizar JSON con fetch

La forma más sencilla de obtener datos de una API es con fetch, que incluye el método .json() para parsear las respuestas JSON en un objeto literal o arreglo JavaScript que pueda utilizarse de forma automática.

Este es un código que utiliza fetch para hacer una petición GET de un chiste con temática de desarrollo de la API gratuita Chuck Norris Jokes:

fetch('https://api.chucknorris.io/jokes/random?category=dev')
  .then(res => res.json()) // el método .json() analiza la respuesta JSON en un objeto literal JS
  .then(data => console.log(data));

Si ejecutas ese código en el navegador, verás algo así en la consola:

{
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
}

Aunque parece un objeto JSON, en realidad es un objeto literal de JavaScript, y puedes usarlo libremente en tu aplicación.

Cómo encadenar JSON con JSON.stringify()

¿Pero qué pasa si quieres enviar datos a una API?

Por ejemplo, digamos que quieres enviar un chiste de Chuck Norris a la API de Chistes de Chuck Norris para que otras personas puedan leerlo después.

En primer lugar, escribirías tu broma como un objeto literal de JS:

const nuevoChiste = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

Entonces, como estás enviando datos a una API, tendrías que convertir tu objeto literal nuevoChiste en una cadena JSON.

Afortunadamente, JavaScript incluye un método superútil para hacer precisamente eso: JSON.stringify():

const nuevoChiste = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

console.log(JSON.stringify(nuevoChiste)); // {"categories":["dev"],"value":"Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."}

console.log(typeof JSON.stringify(nuevoChiste)); // string

Aunque en este ejemplo estamos convirtiendo un objeto literal en una cadena JSON, JSON.stringify() también funciona con arreglos.

Por último, sólo tendría que enviar su chiste JSON a la API con una petición POST. POST.

Tenga en cuenta que la API de Chuck Norris Jokes no tiene esta función. Pero si la tuviera, este es el aspecto que tendría el código:

const nuevoChiste = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

fetch('https://api.chucknorris.io/jokes/submit', { // endpoint falso - API
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(nuevoChiste), // convertir el objeto literal JS en una cadena JSON
})
  .then(res => res.json())
  .then(data => console.log(data))
  .catch(err => {
    console.error(err);
  });

Y así, has analizado el JSON entrante con fetch y has utilizado JSON.stringify() para convertir un objeto literal JS en una cadena JSON.

Cómo trabajar con archivos JSON locales en el navegador

Lamentablemente, no es posible (ni recomendable) cargar un archivo JSON local en el navegador.

fetch arrojará un error si intentas cargar un archivo local. Por ejemplo, digamos que tienes un archivo JSON con algunos chistes:

[
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
chistes.json

Y quieres analizarlo y crear una lista de chistes en una página HTML sencilla.

Si creas una página con lo siguiente y la abres en tu navegador:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width" />
    <title>Obtener JSON local</title>
  </head>
  <script>
    fetch("./chistes.json", { mode: "no-cors" }) // desactivar CORS porque la ruta no contiene http(s)
      .then((res) => res.json())
      .then((data) => console.log(data));
  </script>
</html>
index.html

Verás esto en la consola:

Fetch API cannot load file://<path>/chistes.json. URL scheme "file" is not supported

Por defecto, los navegadores no permiten el acceso a los archivos locales por razones de seguridad. Esto es algo bueno, y no deberías hacer nada para evitar este comportamiento.

En su lugar, lo mejor es convertir el archivo JSON local en JavaScript. Afortunadamente, esto es bastante fácil, ya que la sintaxis de JSON es muy similar a la de JavaScript.

Todo lo que necesitas hacer es crear un nuevo archivo y declarar tu JSON como una variable:

const chistes = [
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
chistes.js

Y añádelo a tu página como un script por separado:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width" />
    <title>Obtener JSON local</title>
  </head>
  <script src="chistes.js"></script>
  <script>
    console.log(chistes);
  </script>
</html>

Podrás utilizar el arreglo de chistes libremente en tu código.

También podrías usar modulos de JavaScript para hacer lo mismo, pero eso está un poco fuera del alcance de este artículo.

¿Pero qué pasa si quieres trabajar con archivos JSON locales y tienes Node.js instalado? Echemos un vistazo a como hacerlo ahora.

Cómo analizar JSON en Node.js

Node.js es un runtime de JavaScript que permite ejecutar JavaScript fuera del navegador. Puedes leer todo sobre Node.js aquí.

Tanto si usas Node.js para ejecutar código localmente en tu ordenador, como si quieres ejecutar aplicaciones web completas en un servidor, es bueno saber cómo trabajar con JSON.

Para los siguientes ejemplos, utilizaremos el mismo archivo chistes.json:

[
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "elgv2wkvt8ioag6xywykbq",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/elgv2wkvt8ioag6xywykbq",
    "value": "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."
  },
  {
    "categories": ["dev"],
    "created_at": "2020-01-05 13:42:19.324003",
    "icon_url": "https://assets.chucknorris.host/img/avatar/chuck-norris.png",
    "id": "ae-78cogr-cb6x9hluwqtw",
    "updated_at": "2020-01-05 13:42:19.324003",
    "url": "https://api.chucknorris.io/jokes/ae-78cogr-cb6x9hluwqtw",
    "value": "There is no Esc key on Chuck Norris' keyboard, because no one escapes Chuck Norris."
  }
]
chistes.json

Cómo analizar un archivo JSON con require()

Empecemos con el método más sencillo.

Si tienes un archivo JSON local, todo lo que necesitas hacer es usar require() para cargarlo como cualquier otro módulo de Node.js:

const chistes = require('./chistes.json');

El archivo JSON será analizado por ti automáticamente y podrás empezar a utilizarlo en tu proyecto:

const chistes = require('./chistes.json');

console.log(chistes[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

Ten en cuenta que esto es síncrono, lo que significa que su programa se detendrá hasta que analice todo el archivo antes de continuar. Los archivos JSON muy grandes pueden hacer que tu programa se ralentice, así que ten cuidado con eso.

Además, debido a que el análisis de JSON de esta manera carga todo en la memoria, es mejor utilizar este método para los archivos JSON estáticos. Si el archivo JSON cambia mientras tu programa está ejecutándose, no tendrás acceso a esos cambios hasta que reinicies tu programa y analices el archivo JSON actualizado.

Cómo analizar un archivo JSON con fs.readFileSync() y JSON.parse()

Esta es la forma más tradicional (a falta de un término mejor) de analizar archivos JSON en proyectos Node.js – leer el archivo con el módulo fs (file system), y luego analizarlo con JSON.parse().

Veamos cómo hacer esto con el método fs.readFileSync(). Primero, añade el módulo fs a tu proyecto:

const fs = require('fs');

Luego, crea una nueva variable para almacenar la salida del archivo chistes.json y establécela igual a fs.readFileSync():

const fs = require('fs');
const archivoChistes = fs.readFileSync();

fs.readFileSync() toma un par de argumentos. El primero es la ruta del archivo que quieres leer:

const fs = require('fs');
const archivoChistes = fs.readFileSync('./chistes.json');

Pero si ahora registras archivoChistese en la consola, verías algo como esto:

<Buffer 5b 0a 20 20 7b 0a 20 20 20 20 22 63 61 74 65 67 6f 72 69 65 73 22 3a 20 5b 22 64 65 76 22 5d 2c 0a 20 20 20 20 22 63 72 65 61 74 65 64 5f 61 74 22 3a ... 788 more bytes>

Eso sólo significa que el módulo fs está leyendo el archivo, pero no sabe la codificación o el formato del archivo. fs se puede utilizar para cargar casi cualquier archivo, y no sólo los basados en texto como JSON, por lo que tenemos que decirle cómo está codificado el archivo.

Para los archivos basados en texto, la codificación suele ser utf8:

const fs = require('fs');
const archivoChistes = fs.readFileSync('./chistes.json', 'utf8');

Ahora bien, si se registra archivoChistes en la consola, se verá el contenido del archivo.

Pero hasta ahora sólo estamos leyendo el archivo, y sigue siendo una cadena. Necesitaremos utilizar otro método para convertir archivoChistes en un objeto o arreglo JavaScript utilizable.

Para ello, utilizaremos JSON.parse():

const fs = require('fs');
const archivoChistes = fs.readFileSync('./chistes.json', 'utf8');
const chistes = JSON.parse(archivoChistes);

console.log(chistes[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

Como su nombre indica,  JSON.parse() toma una cadena JSON y la convierte en un objeto literal o arreglo de JavaScript.

Al igual que con el método anterior require, fs.readFileSync() es un método síncrono, lo que significa que podría hacer que su programa se ralentice si está leyendo un archivo grande, JSON o de otro tipo

Además, sólo lee el archivo una vez y lo carga en la memoria. Si el archivo cambia, tendrá que leerlo de nuevo en algún momento. Para hacer las cosas más fáciles, es posible que desee crear una función simple para leer los archivos.

Así es cómo podría verse:

const fs = require('fs');
const leerArchivo = path => fs.readFileSync(path, 'utf8');

const archivoChistes1 = leerArchivo('./chistes.json');
const chistes1 = JSON.parse(archivoChistes1);

console.log(chistes1[0].value); // "Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris."

// el archivo chistes.json cambia en algún momento

const archivoChistes2 = leerArchivo('./chistes.json');
const chistes2 = JSON.parse(archivoChistes2);

console.log(chistes2[0].value); // "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."

Cómo analizar JSON con fs.readFile() y JSON.parse()

El método fs.readFile() es muy similar a fs.readFileSync(), excepto que funciona de forma asíncrona. Esto es genial si tienes un archivo grande que leer y no quieres que retenga el resto de tu código.

Este es un ejemplo básico:

const fs = require('fs');

fs.readFile('./chistes.json', 'utf8');

Hasta ahora esto se parece a lo que hicimos con fs.readFileSync(), excepto que no lo estamos asignando a una variable como archivoChistes. Como es asíncrono, cualquier código posterior a fs.readFile() se ejecutará antes de que termine de leer el archivo.

En su lugar, usaremos una función calback y analizaremos el JSON dentro de ella:

const fs = require('fs');

fs.readFile('./chistes.json', 'utf8', (err, data) => {
  if (err) console.error(err);
  const chistes = JSON.parse(data);

  console.log(chistes[0].value);
});

console.log("Esto se ejecutará primero");

Que imprime lo siguiente en la consola:

Esto se ejecutará primero
Chuck Norris's keyboard doesn't have a Ctrl key because nothing controls Chuck Norris.

Al igual que con fs.readFileSync(), fs.readFile() carga el archivo en la memoria, lo que significa que tendrá que leer el archivo de nuevo si cambia.

Además, aunque fs.readFile() es asíncrona, al final carga todo el archivo que está leyendo en la memoria. Si tienes un archivo masivo, puede ser mejor buscar en Node.js streams en su lugar.

Cómo encadenar JSON con JSON.stringify() en Node.js

Por último, si estás analizando JSON con Node.js, es muy probable que necesites retornar JSON en algún momento, tal vez como una respuesta de la API.

Por suerte, esto funciona de la misma manera que en el navegador - sólo tienes que utilizar JSON.stringify() para convertir los objetos literales de JavaScript o arreglos en una cadena JSON:

const nuevoChiste = {
  categories: ['dev'],
  value: "Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."
};

console.log(JSON.stringify(nuevoChiste)); // {"categories":["dev"],"value":"Chuck Norris's keyboard is made up entirely of Cmd keys because Chuck Norris is always in command."}

Y eso es todo. Hemos cubierto casi todo lo que necesitas saber sobre cómo trabajar con JSON en el navegador y en los proyectos de Node.js.

Ahora sal a la pista y analiza o encadena los JSON a tu gusto.

¿Se me ha olvidado algo? ¿Cómo analizas JSON en tus proyectos? Hacemelo saber atravez de Twitter.