Rick and Morty Explorer: Aplicación web con JavaScript, API REST y LocalStorage
Visión General
Rick and Morty Explorer es una aplicación web de página única (SPA) desarrollada como parte del entregable del módulo de JavaScript del Máster en Desarrollo Web Full Stack. El proyecto demuestra el consumo de APIs REST, manejo de peticiones asíncronas, manipulación avanzada del DOM, gestión de estado, persistencia con LocalStorage y una experiencia de usuario cuidada.
La aplicación consume la API oficial de Rick and Morty y permite explorar personajes y episodios de la serie, con funcionalidades completas de búsqueda, filtrado, paginación y un sistema de favoritos que persiste entre sesiones.
Estructura del Proyecto
rickandmorty-explorer/
├── index.html # Estructura principal (SPA)
├── css/
│ └── styles.css # Estilos globales, variables CSS, responsive
├── js/
│ ├── api.js # Cliente API con sistema de caché
│ ├── favorites.js # Gestión de favoritos (LocalStorage)
│ ├── ui.js # Renderizado y manipulación del DOM
│ └── app.js # Lógica principal y control de eventos
└── README.md
Arquitectura y Patrones
Separación de Responsabilidades
El código se organiza en cuatro módulos independientes siguiendo el principio de separación de concerns:
| Módulo | Responsabilidad |
|---|---|
api.js | Comunicación con la API, caché de peticiones |
favorites.js | Gestión del estado de favoritos, persistencia |
ui.js | Renderizado, manipulación del DOM, modales |
app.js | Eventos, estado global, coordinación entre módulos |
Sistema de Caché
Implementación de un sistema de caché con Map() que almacena las respuestas de la API, evitando peticiones redundantes:
class RickMortyAPI {
constructor() {
this.cache = new Map();
}
async fetchWithCache(url) {
if (this.cache.has(url)) {
return this.cache.get(url);
}
const response = await fetch(url);
const data = await response.json();
this.cache.set(url, data);
return data;
}
}
Patrón de Estado Global
La aplicación mantiene un estado centralizado en app.js:
let currentPage = 1;
let currentFilters = { name: '', status: '', species: '' };
let currentView = 'characters';
let currentEpisodesPage = 1;
let totalPages = 1;
let totalEpisodesPages = 1;
Funcionalidades Implementadas
1. Exploración de Personajes
- Listado paginado: Grid responsive con imagen, nombre, estado y especie
- Búsqueda en tiempo real: Filtra mientras el usuario escribe
- Filtros combinados: Estado (Vivo/Muerto/Desconocido) + Especie (Humano, Alienígena, Robot, etc.)
- Persistencia de filtros: Al cambiar de página, los filtros se mantienen
2. Detalle de Personaje (Modal)
Al hacer clic en cualquier personaje se abre un modal con:
- Imagen en alta resolución
- Nombre completo
- Estado, especie, tipo, género
- Origen y ubicación actual
- Lista de episodios donde aparece (limitada a 10 por rendimiento)
3. Exploración de Episodios
- Listado paginado de episodios
- Búsqueda por nombre del episodio
- Información mostrada: nombre, fecha de emisión, código (ej: S01E01)
4. Detalle de Episodio (Modal)
- Nombre y código del episodio
- Fecha de emisión
- Lista completa de personajes que aparecen
- Navegación bidireccional: Al hacer clic en un personaje, se abre su detalle
5. Sistema de Favoritos
- Marcar/desmarcar personajes desde la tarjeta o desde el modal
- Persistencia automática con LocalStorage
- Contador dinámico visible en el botón de favoritos
- Vista independiente que muestra solo los personajes marcados
- Los favoritos se mantienen al recargar la página
6. Manejo de Estados
- Loading states: Spinners animados mientras cargan datos
- Error handling: Mensajes contextuales que se auto-ocultan
- Empty states: Mensajes claros cuando no hay resultados
Tecnologías Implementadas
Frontend
- HTML5: Estructura semántica, modales, layout SPA
- CSS3: Variables CSS, Flexbox, Grid, animaciones, media queries
- JavaScript (ES6+): Async/Await, fetch API, Promises, Map(), localStorage
API Externa
- Rick and Morty API: Endpoints de
/charactery/episodecon paginación integrada
Librerías Externas
- Font Awesome 6: Iconografía
- Google Fonts (Inter): Tipografía profesional
Características Técnicas Destacadas
Peticiones Concurrentes con Promise.all
Para mostrar episodios en el detalle de un personaje:
const episodeUrls = character.episode || [];
const episodes = await Promise.all(
episodeUrls.slice(0, 10).map(url => fetch(url).then(r => r.json()))
);
Navegación Bidireccional
Desde el detalle de episodio se puede acceder al detalle del personaje:
document.querySelectorAll('.character-link').forEach(el => {
el.addEventListener('click', async () => {
const charId = parseInt(el.dataset.id);
const character = await api.getCharacterById(charId);
// Renderizar detalle del personaje
});
});
Prevención de XSS con escapeHtml
escapeHtml(str) {
const div = document.createElement('div');
div.textContent = str;
return div.innerHTML;
}
Gestión de Favoritos con LocalStorage
class FavoritesManager {
toggleFavorite(character) {
if (this.isFavorite(character.id)) {
this.removeFavorite(character.id);
} else {
this.addFavorite(character);
}
this.saveFavorites();
}
saveFavorites() {
localStorage.setItem(this.storageKey, JSON.stringify(this.favorites));
}
}
Responsive Design
El proyecto implementa una estrategia mobile-first con breakpoints progresivos:
| Breakpoint | Pantalla | Grid personajes | Layout |
|---|---|---|---|
| Base | Móvil (<768px) | 1 columna | Navegación apilada |
| 768px+ | Tablet | 2-3 columnas | Header horizontal |
| 1024px+ | Desktop | 4 columnas | Filtros en paralelo |
Ejemplo de media queries:
/* Tablet */
@media (min-width: 768px) {
.characters-grid {
grid-template-columns: repeat(auto-fill, minmax(12.5rem, 1fr));
}
}
/* Desktop */
@media (min-width: 1024px) {
.filters-section {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-xl);
}
}
UX/UI Destacado
Animaciones y Transiciones
- Fade-in al cambiar de vista
- Hover effects en tarjetas (elevación y cambio de borde)
- Transiciones suaves en botones y modales
Feedback Visual
- Spinner animado durante cargas
- Mensajes de error con color rojo y auto-ocultamiento
- Botones de paginación deshabilitados visualmente en límites
- Corazón relleno/vacío para estado de favorito
Accesibilidad
- Atributos
aria-labelen botones - Estructura semántica con header, main, nav
loading="lazy"en imágenes para rendimiento
Aprendizajes Clave
Este proyecto ha permitido consolidar los siguientes conceptos fundamentales:
- Consumo de APIs REST: Peticiones asíncronas con
fetchy manejo de errores - Gestión de estado: Variables globales, sincronización entre módulos
- Patrón MVC ligero: Separación clara entre datos, UI y lógica de control
- Persistencia local: Uso de LocalStorage para guardar preferencias
- Optimización de rendimiento: Sistema de caché, lazy loading, límite de episodios
- Eventos complejos: Delegación de eventos, eventos personalizados (
CustomEvent) - Diseño responsive: Mobile-first, CSS Grid, Flexbox, media queries
Enlaces
Conclusión
Rick and Morty Explorer es una aplicación completa que demuestra un dominio sólido de JavaScript en un contexto real:
- API REST: Consumo correcto de endpoints paginados con async/await
- DOM avanzado: Renderizado dinámico, modales, eventos delegados
- Persistencia: Implementación robusta de LocalStorage
- UX: Filtros combinados, búsqueda en tiempo real, feedback visual
- Arquitectura: Código modular, mantenible y escalable
- Rendimiento: Sistema de caché y optimización de peticiones
La aplicación cumple con todos los requisitos del enunciado y añade valor con características adicionales como el sistema de caché, la navegación bidireccional entre personajes y episodios, y una interfaz de usuario cuidada y responsive.