1. ¿Qué es JSON?
JSON (JavaScript Object Notation) es un formato de texto ligero para intercambiar datos. Es el estándar de facto para comunicación entre cliente y servidor.
Características
- ? Fácil de leer y escribir para humanos
- ? Fácil de parsear para máquinas
- ? Independiente del lenguaje (no solo JavaScript)
- ? Soporta estructuras anidadas
Sintaxis JSON
{
"nombre": "Ana García",
"edad": 28,
"esEstudiante": false,
"habilidades": ["JavaScript", "Python", "CSS"],
"direccion": {
"ciudad": "Madrid",
"codigoPostal": "28001"
},
"email": null
}
- Las claves DEBEN estar entre comillas dobles:
"nombre" - Los strings DEBEN usar comillas dobles:
"texto" - NO se permiten comentarios
- NO se permiten trailing commas:
{ "a": 1, }? - Solo tipos primitivos: string, number, boolean, null, array, object
JSON vs Objetos JavaScript
| Aspecto | JSON | Objeto JS |
|---|---|---|
| Tipo | Texto (string) | Objeto en memoria |
| Claves | "comillas obligatorias" | Con o sin comillas |
| Funciones | ? No soportadas | ? Soportadas |
| Undefined | ? No existe | ? Existe |
| Comentarios | ? No permitidos | ? Permitidos |
2. JSON.parse() y JSON.stringify()
JSON.stringify() - Objeto ? Texto
Convierte un objeto JavaScript en texto JSON:
const usuario = {
nombre: 'Carlos',
edad: 30,
activo: true,
hobbies: ['leer', 'programar']
};
// Convertir a JSON string
const jsonString = JSON.stringify(usuario);
console.log(jsonString);
// '{"nombre":"Carlos","edad":30,"activo":true,"hobbies":["leer","programar"]}'
console.log(typeof jsonString); // "string"
Parámetros opcionales de stringify()
const datos = {
id: 1,
nombre: 'Producto',
precio: 99.99,
privado: 'no mostrar'
};
// Parámetro 2: Replacer (filtrar propiedades)
const jsonFiltrado = JSON.stringify(datos, ['id', 'nombre', 'precio']);
console.log(jsonFiltrado); // {"id":1,"nombre":"Producto","precio":99.99}
// Parámetro 3: Espaciado (para legibilidad)
const jsonBonito = JSON.stringify(datos, null, 2);
console.log(jsonBonito);
/*
{
"id": 1,
"nombre": "Producto",
"precio": 99.99,
"privado": "no mostrar"
}
*/
JSON.parse() - Texto ? Objeto
Convierte texto JSON en un objeto JavaScript:
const jsonTexto = '{"nombre":"Laura","edad":25,"skills":["JS","CSS"]}';
// Convertir a objeto
const objeto = JSON.parse(jsonTexto);
console.log(objeto.nombre); // "Laura"
console.log(objeto.edad); // 25
console.log(objeto.skills); // ["JS", "CSS"]
console.log(typeof objeto); // "object"
Manejo de Errores
const jsonInvalido = '{ nombre: "error" }'; // Sin comillas en clave
try {
const obj = JSON.parse(jsonInvalido);
} catch (error) {
console.error('JSON inválido:', error.message);
// JSON inválido: Unexpected token n in JSON at position 2
}
3. Fetch API: Peticiones HTTP
Fetch es la API (Application Programming Interface, que es un conjunto de reglas que permiten que diferentes aplicaciones o partes de un código se comuniquen entre sí) moderna para hacer peticiones HTTP. Reemplaza a XMLHttpRequest y usa Promesas.
Sintaxis Básica
// GET básico
fetch('https://api.example.com/users')
.then(response => response.json()) // Parsear JSON
.then(data => console.log(data)) // Usar datos
.catch(error => console.error(error)); // Manejar errores
Con Async/Await (Forma Moderna)
async function obtenerUsuarios() {
try {
const response = await fetch('https://api.example.com/users');
const usuarios = await response.json();
console.log(usuarios);
} catch (error) {
console.error('Error:', error);
}
}
obtenerUsuarios();
fetch() NO rechaza la promesa con errores HTTP (404, 500,
etc.). Solo rechaza con errores de red. Debes verificar response.ok manualmente.
4. El Objeto Response
Cuando fetch() se resuelve, devuelve un objeto Response:
Propiedades Importantes
| Propiedad | Descripción |
|---|---|
response.ok |
true si status 200-299 |
response.status |
Código HTTP (200, 404, 500...) |
response.statusText |
Texto del status ("OK", "Not Found"...) |
response.headers |
Headers de la respuesta |
response.url |
URL final (después de redirects) |
Métodos de Lectura del Body
const response = await fetch('https://api.example.com/data');
// Dependiendo del tipo de respuesta:
const json = await response.json(); // Para JSON
const texto = await response.text(); // Para texto plano
const blob = await response.blob(); // Para archivos binarios
const formData = await response.formData(); // Para formularios
Verificar Éxito de la Petición
async function obtenerDatos() {
try {
const response = await fetch('https://api.example.com/users/999');
// ? Verificar si la respuesta es exitosa
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Hubo un problema:', error);
}
}
5. Métodos HTTP con Fetch
GET - Obtener Datos
// GET es el método por defecto
async function obtenerUsuario(id) {
const response = await fetch(`https://api.example.com/users/${id}`);
if (!response.ok) throw new Error('Usuario no encontrado');
return await response.json();
}
obtenerUsuario(1).then(console.log);
POST - Crear Datos
async function crearUsuario(usuario) {
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(usuario)
});
if (!response.ok) throw new Error('Error al crear usuario');
return await response.json();
}
const nuevoUsuario = {
nombre: 'Ana',
email: 'ana@example.com'
};
crearUsuario(nuevoUsuario).then(console.log);
PUT - Actualizar Completo
async function actualizarUsuario(id, datosCompletos) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datosCompletos)
});
return await response.json();
}
PATCH - Actualizar Parcial
async function actualizarParcial(id, cambios) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(cambios)
});
return await response.json();
}
// Solo actualizar el email
actualizarParcial(1, { email: 'nuevo@email.com' });
DELETE - Eliminar
async function eliminarUsuario(id) {
const response = await fetch(`https://api.example.com/users/${id}`, {
method: 'DELETE'
});
if (!response.ok) throw new Error('Error al eliminar');
// Algunas APIs devuelven 204 No Content
if (response.status === 204) {
return { mensaje: 'Eliminado correctamente' };
}
return await response.json();
}
🛑 Cancelar Peticiones: AbortController
A veces una petición tarda demasiado o el usuario se va a otra página. Puedes cancelarla para ahorrar recursos.
const controller = new AbortController();
const signal = controller.signal;
// 1. Pasamos la señal al fetch
fetch('https://api.lenta.com/datos', { signal })
.catch(err => {
if (err.name === 'AbortError') {
console.log('Petición cancelada por el usuario');
}
});
// 2. Cuando queramos cancelar:
controller.abort();
6. Trabajando con Headers
Headers Comunes
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json', // Tipo de contenido
'Authorization': 'Bearer TOKEN_AQUI', // Auth token
'Accept': 'application/json', // Tipo esperado
'X-Custom-Header': 'valor' // Header custom
},
body: JSON.stringify({ dato: 'valor' })
};
fetch('https://api.example.com/data', options);
Leer Headers de la Respuesta
const response = await fetch('https://api.example.com/data');
// Obtener un header específico
const contentType = response.headers.get('Content-Type');
console.log(contentType); // "application/json"
// Verificar si existe un header
if (response.headers.has('X-RateLimit-Remaining')) {
console.log('Rate limit:', response.headers.get('X-RateLimit-Remaining'));
}
// Iterar todos los headers
for (const [key, value] of response.headers) {
console.log(`${key}: ${value}`);
}
7. Ejemplo Real: JSONPlaceholder API
JSONPlaceholder es una API fake gratuita para practicar.
CRUD Completo
const API_URL = 'https://jsonplaceholder.typicode.com';
// 1. Obtener todos los posts (GET)
async function obtenerPosts() {
const response = await fetch(`${API_URL}/posts`);
const posts = await response.json();
console.log('Posts:', posts.length);
return posts;
}
// 2. Obtener un post específico (GET)
async function obtenerPost(id) {
const response = await fetch(`${API_URL}/posts/${id}`);
if (!response.ok) {
throw new Error('Post no encontrado');
}
return await response.json();
}
// 3. Crear un post (POST)
async function crearPost(datos) {
const response = await fetch(`${API_URL}/posts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datos)
});
const nuevoPost = await response.json();
console.log('Post creado con ID:', nuevoPost.id);
return nuevoPost;
}
// 4. Actualizar post (PUT)
async function actualizarPost(id, datos) {
const response = await fetch(`${API_URL}/posts/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(datos)
});
return await response.json();
}
// 5. Eliminar post (DELETE)
async function eliminarPost(id) {
const response = await fetch(`${API_URL}/posts/${id}`, {
method: 'DELETE'
});
if (response.ok) {
console.log(`Post ${id} eliminado`);
}
}
// Usar las funciones
async function demo() {
try {
// Obtener posts
const posts = await obtenerPosts();
console.log('Primer post:', posts[0]);
// Obtener un post específico
const post = await obtenerPost(1);
console.log('Post 1:', post);
// Crear nuevo post
const nuevo = await crearPost({
title: 'Mi Post',
body: 'Contenido del post',
userId: 1
});
console.log('Creado:', nuevo);
// Actualizar
const actualizado = await actualizarPost(1, {
id: 1,
title: 'Título Actualizado',
body: 'Contenido actualizado',
userId: 1
});
console.log('Actualizado:', actualizado);
// Eliminar
await eliminarPost(1);
} catch (error) {
console.error('Error:', error);
}
}
demo();
8. Query Parameters (Parámetros de URL)
Para filtrar, paginar o buscar datos:
Forma Manual
const userId = 1;
const limite = 10;
const url = `https://api.example.com/posts?userId=${userId}&_limit=${limite}`;
const response = await fetch(url);
const posts = await response.json();
Con URLSearchParams (Recomendado)
const params = new URLSearchParams({
userId: 1,
_limit: 10,
_sort: 'id',
_order: 'desc'
});
const url = `https://jsonplaceholder.typicode.com/posts?${params}`;
console.log(url);
// https://jsonplaceholder.typicode.com/posts?userId=1&_limit=10&_sort=id&_order=desc
const response = await fetch(url);
const posts = await response.json();
9. Manejo de Errores Robusto
Patrón Completo
async function peticionRobusta(url, options = {}) {
try {
// 1. Hacer la petición
const response = await fetch(url, options);
// 2. Verificar errores HTTP
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(
`HTTP ${response.status}: ${errorData.message || response.statusText}`
);
}
// 3. Parsear respuesta
const data = await response.json();
return { success: true, data };
} catch (error) {
// Si no hay conexión o error de red
if (error.name === 'TypeError') {
return {
success: false,
error: 'Error de conexión. Verifica tu internet.'
};
}
// Otros errores
return {
success: false,
error: error.message
};
}
}
// Uso
const resultado = await peticionRobusta('https://api.example.com/users');
if (resultado.success) {
console.log('Datos:', resultado.data);
} else {
console.error('Error:', resultado.error);
}
10. Añadir Timeout a Fetch
Fetch no tiene timeout incorporado. Usa AbortController:
async function fetchConTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId);
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
throw new Error('La petición tardó demasiado (timeout)');
}
throw error;
}
}
// Uso
try {
const data = await fetchConTimeout('https://api.example.com/slow', 3000);
console.log(data);
} catch (error) {
console.error(error.message);
}
11. Ejercicios Prácticos
Ejercicio 1: JSON Básico
Convierte este objeto a JSON y luego de vuelta a objeto:
const producto = {
id: 101,
nombre: 'Laptop',
precio: 899.99,
disponible: true
};
// 1. Convertir a JSON string
// 2. Parsear de vuelta a objeto
// 3. Mostrar el nombre
Ejercicio 2: Fetch Básico
Obtén 5 posts de JSONPlaceholder:
// URL: https://jsonplaceholder.typicode.com/posts?_limit=5
// 1. Hacer fetch
// 2. Convertir a JSON
// 3. Mostrar los títulos en consola
Ejercicio 3: POST con Fetch
Crea un nuevo usuario en JSONPlaceholder:
// URL: https://jsonplaceholder.typicode.com/users
// Datos: { name: 'Tu nombre', email: 'tu@email.com', username: 'tunombre' }
// Muestra el ID del usuario creado
Ejercicio 4: Manejo de Errores
Intenta obtener un post que no existe (ID 9999) y maneja el error:
// URL: https://jsonplaceholder.typicode.com/posts/9999
// Usa try/catch y verifica response.ok
Resumen
- ? JSON es el formato estándar para intercambio de datos
- ?
JSON.stringify()convierte objeto ? texto - ?
JSON.parse()convierte texto ? objeto - ?
fetch()es la API moderna para HTTP - ? Siempre verifica
response.okantes de usar los datos - ? Usa async/await para código más limpio
- ? Maneja errores con try/catch
Siguiente paso: En la próxima lección aprenderás sobre LocalStorage y SessionStorage para guardar datos en el navegador.