Cómo crear un playground API interactivo en React
Un componente playground API React muestra un selector de endpoint, una barra de URL, un body de petición JSON opcional y un panel de respuesta con resaltado de sintaxis. Al pulsar Run se dispara una petición simulada de 800ms y después se revela la respuesta JSON mediante AnimatePresence de Framer Motion.
- Stack: React 18 + Framer Motion 11 + Lucide React + tokens CSS de Tailwind v4, ~540 líneas.
- Un tokenizador JSON propio resalta las claves (color de acento), valores string (verde), números (amber) y booleanos/null (morado) sin ninguna librería de sintaxis externa.
- Accesible: todos los elementos interactivos son botones nativos; el botón Run se desactiva y muestra un spinner durante el estado pendiente.
- Totalmente responsive, la barra de cabecera se ajusta en pantallas pequeñas; la cuadrícula petición/respuesta pasa a una sola columna cuando no hay body.
- El copiar al portapapeles usa navigator.clipboard.writeText con un estado de confirmación visual de 2 segundos.
Una sección de playground API permite a los desarrolladores probar endpoints HTTP directamente dentro de tu página de documentación, sin abrir Postman ni cambiar de contexto. Este componente React reúne la selección de endpoint, la visualización del body, un flujo de ejecución simulado y un panel de respuesta JSON con resaltado de sintaxis en una sola sección autónoma.
Anatomía
El componente tiene tres zonas visuales. Una barra de cabecera contiene el selector de endpoint (un dropdown animado con AnimatePresence), la barra de URL que muestra base + ruta, y el botón Run con estado de carga. Debajo, un área de contenido se divide en dos columnas cuando el endpoint seleccionado tiene un body de petición: la columna izquierda muestra el body JSON y la derecha la respuesta. Cuando no hay body, la respuesta ocupa todo el ancho. Un badge tipo pill con un icono Braces se sitúa encima del título como marcador de categoría.
Cómo funciona
El estado se gestiona con cuatro booleanos: isRunning, showResponse, copied y showEndpointList. Pulsar Run pone isRunning a true y showResponse a false, y luego un setTimeout de 800ms invierte ambos. El panel de respuesta usa AnimatePresence en modo wait para fundir entre tres estados con key: 'loading' (spinner centrado), 'response' (aparece desde y+8) y 'empty' (texto indicativo atenuado). El tokenizador JSON es un parser carácter por carácter que identifica claves, valores string, números y booleanos mediante regex, y devuelve un array de segmentos coloreados renderizados como spans inline dentro de un elemento pre con números de línea.
Cómo crearlo en React
Definir la estructura de datos de los endpoints
Crea una interfaz ApiEndpoint con method, path, label, un body string opcional y un response string. La respuesta es JSON preserializado, esto mantiene el componente puramente presentacional y evita cualquier llamada de red real en la demo.
interface ApiEndpoint { method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; path: string; label: string; body?: string; response: string; }Construir el dropdown de endpoint animado
Alterna showEndpointList con el botón selector. Envuelve la lista desplegable en AnimatePresence y anímala con opacidad y un desplazamiento y de 4px. Al hacer clic en un item, actualiza selectedIdx, cierra la lista y reinicia showResponse para que la respuesta anterior no persista.
<AnimatePresence> {showEndpointList && ( <motion.div initial={{ opacity: 0, y: -4 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -4 }} transition={{ duration: 0.15 }} style={{ position: "absolute", top: "calc(100% + 4px)", zIndex: 50 }} > {endpoints.map((ep, i) => ( <button key={i} onClick={() => { setSelectedIdx(i); setShowEndpointList(false); setShowResponse(false); }}> {ep.label} </button> ))} </motion.div> )} </AnimatePresence>Simular el ciclo de carga y respuesta
El callback handleRun pone isRunning a true y limpia showResponse, y luego se resuelve tras 800ms. En el panel de respuesta, usa AnimatePresence con mode='wait' y tres hijos con key para que React desmonte por completo un estado antes de montar el siguiente.
const handleRun = useCallback(() => { setIsRunning(true); setShowResponse(false); setTimeout(() => { setIsRunning(false); setShowResponse(true); }, 800); }, []);Escribir el tokenizador de sintaxis JSON
Implementa tokenizeLine como un bucle while que detecta patrones de izquierda a derecha: clave JSON (palabra entre comillas seguida de dos puntos), valor string, entero o booleano/null. Cada coincidencia añade un segmento con texto y una cadena de color CSS. Renderiza los segmentos como spans coloreados dentro de un bloque pre, con una columna de números de línea generada mediante map sobre las líneas divididas.
function tokenizeLine(line: string): TokenSegment[] { const segments: TokenSegment[] = []; let remaining = line; while (remaining.length > 0) { const keyMatch = remaining.match(/^("[w_]+")(s*:s*)/); if (keyMatch) { segments.push({ text: keyMatch[1], color: "var(--color-accent)" }); segments.push({ text: keyMatch[2], color: "var(--color-foreground-muted)" }); remaining = remaining.slice(keyMatch[0].length); continue; } // ... string, number, boolean matches } return segments; }
Cuándo usarlo
Recurre a este componente en landing pages de productos para desarrolladores, sitios de documentación API o páginas de onboarding SaaS donde mostrar un ciclo de petición con aspecto real genera confianza más rápido que un simple bloque de código. Funciona especialmente bien cuando tu API devuelve JSON limpio y quieres destacar endpoints concretos. Evítalo en páginas de marketing dirigidas al gran público donde el enfoque técnico confundiría a visitantes no desarrolladores, y no lo uses como cliente HTTP real, es una demo presentacional, no una capa de red.
Usado por
- Stripe, La referencia API de Stripe incorpora paneles de petición/respuesta interactivos para cada endpoint, con badges de método HTTP coloreados y respuestas JSON copiables.
- Postman, La interfaz web de Postman popularizó la disposición selector de endpoint + barra de URL + panel de respuesta que este componente condensa en una sección integrable.
- Resend, La documentación de Resend usa exploradores de API en panel dividido con código de color por método HTTP y vistas previas de respuestas JSON con resaltado de sintaxis.
- Supabase, Supabase ofrece playgrounds API en vivo en su documentación, permitiendo a los desarrolladores lanzar peticiones reales contra su proyecto desde la propia página de documentación.
FAQ
¿Este componente hace peticiones HTTP reales?
No. Los datos de respuesta están predefinidos en las props del endpoint, y el retardo de 800ms es un setTimeout. Sustitúyelo por una llamada fetch real si quieres peticiones en vivo, pero conserva la máquina de estados AnimatePresence de carga/respuesta, gestiona el ciclo asíncrono de forma limpia.
¿Cómo añado cabeceras HTTP personalizadas o parámetros de consulta?
Extiende la interfaz ApiEndpoint con campos opcionales headers y params, y luego renderízalos como secciones de panel adicionales entre la barra de URL y el área de respuesta. La cuadrícula de columnas divididas ya admite zonas extra sin cambios de maquetación.
¿Puedo usar una librería de resaltado de sintaxis real en lugar del tokenizador propio?
Sí. Sustituye el componente JsonHighlight y la función tokenizeLine por Prism.js, Shiki o highlight.js. La maquetación circundante y las animaciones de AnimatePresence permanecen sin cambios, el tokenizador está aislado en esas dos funciones.
¿Cómo muestro un código de estado y un tiempo de respuesta reales?
Guarda performance.now() antes del fetch y calcula el delta al resolverse. Añade status y latencyMs a un objeto de estado de resultado, y luego muéstralos en la fila de cabecera de la respuesta donde ahora están las cadenas fijas '200 OK' y '124ms'.