Volver
Ctrl+Space
◑
Copiar
Descargar
Restaurar
Ejecutar
Ctrl+Enter
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Fetch API — Ejemplo 2</title> <style> body { font-family: Arial, sans-serif; padding: 20px; background: #fff; max-width: 640px; } h3 { margin: 22px 0 8px; font-size: 15px; color: #333; } .campo { margin-bottom: 12px; } label { display: block; font-size: 12px; font-weight: bold; color: #555; text-transform: uppercase; letter-spacing: 0.4px; margin-bottom: 4px; } input, textarea, select { width: 100%; padding: 9px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; box-sizing: border-box; font-family: inherit; outline: none; transition: border-color 0.2s; } input:focus, textarea:focus, select:focus { border-color: #F7DF1E; } textarea { resize: vertical; min-height: 80px; } button { padding: 9px 20px; background: #F7DF1E; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; font-size: 14px; margin-right: 6px; transition: background 0.15s; } button:hover { background: #e6cc00; } button:disabled { background: #eee; color: #aaa; cursor: not-allowed; } .btn-danger { background: #fee2e2; color: #dc2626; } .btn-danger:hover { background: #fca5a5; } .resultado { margin-top: 14px; padding: 14px; border-radius: 8px; font-size: 13px; display: none; } .resultado.ok { background: #f0fdf4; border: 1px solid #86efac; color: #166534; } .resultado.err { background: #fef2f2; border: 1px solid #fca5a5; color: #991b1b; } .resultado.loading { background: #fffde7; border: 1px solid #F7DF1E; color: #856404; display: block; } .json-box { background: #1a1a1a; color: #a5b4fc; border-radius: 6px; padding: 12px; font-family: monospace; font-size: 12px; white-space: pre; overflow-x: auto; margin-top: 10px; } .metodos { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; } .badge-method { display: inline-block; font-size: 11px; font-weight: bold; padding: 3px 10px; border-radius: 4px; font-family: monospace; } .get { background: #dbeafe; color: #1d4ed8; } .post { background: #dcfce7; color: #166534; } .put { background: #fef9c3; color: #854d0e; } .del { background: #fee2e2; color: #991b1b; } .separador { border: none; border-top: 1px solid #eee; margin: 24px 0; } .log { background: #f9f9f9; border: 1px solid #eee; border-radius: 6px; padding: 10px 14px; font-family: monospace; font-size: 12px; max-height: 120px; overflow-y: auto; margin-top: 10px; } .log div { padding: 2px 0; } .log .ok-log { color: #166534; } .log .err-log { color: #991b1b; } </style> </head> <body> <h2>Fetch API — POST y manejo de errores</h2> <h3>1. Crear un post (POST)</h3> <div class="campo"> <label>Título</label> <input type="text" id="titulo" value="Mi primer post con fetch" maxlength="100"> </div> <div class="campo"> <label>Contenido</label> <textarea id="cuerpo">Este contenido fue enviado con fetch y el método POST.</textarea> </div> <div class="campo"> <label>Usuario ID (1–10)</label> <input type="number" id="userId" value="1" min="1" max="10" style="width:80px"> </div> <button id="btnPost">Enviar POST</button> <div class="resultado" id="resultadoPost"></div> <hr class="separador"> <h3>2. Actualizar un post (PUT)</h3> <div class="campo"> <label>ID del post a actualizar</label> <input type="number" id="putId" value="1" min="1" max="100" style="width:80px"> </div> <div class="campo"> <label>Nuevo título</label> <input type="text" id="putTitulo" value="Título actualizado con PUT"> </div> <button id="btnPut">Enviar PUT</button> <div class="resultado" id="resultadoPut"></div> <hr class="separador"> <h3>3. Eliminar un post (DELETE)</h3> <div class="campo"> <label>ID del post a eliminar</label> <input type="number" id="deleteId" value="1" min="1" max="100" style="width:80px"> </div> <button id="btnDelete" class="btn-danger">Enviar DELETE</button> <div class="resultado" id="resultadoDelete"></div> <hr class="separador"> <h3>4. Probar errores HTTP (404, 500)</h3> <div class="metodos"> <button id="btn404">Probar 404</button> <button id="btn500">Probar 500</button> </div> <div class="log" id="logErrores">Hacé clic en los botones para ver cómo se manejan los errores...</div> <script> // Fetch API en JavaScript - Ejemplo 2: POST, PUT, DELETE y errores const BASE = "https://jsonplaceholder.typicode.com"; // ── Helper: mostrar resultado ───────────────────────────────────────── function mostrar(id, tipo, html) { const div = document.getElementById(id); div.className = `resultado ${tipo}`; div.style.display = "block"; div.innerHTML = html; } // ── 1. POST ─────────────────────────────────────────────────────────── document.getElementById("btnPost").addEventListener("click", async function() { const titulo = document.getElementById("titulo").value.trim(); const cuerpo = document.getElementById("cuerpo").value.trim(); const userId = parseInt(document.getElementById("userId").value); if (!titulo || !cuerpo) { mostrar("resultadoPost", "err", "❌ Completá el título y el contenido"); return; } this.disabled = true; mostrar("resultadoPost", "loading", "⏳ Enviando POST..."); try { const response = await fetch(`${BASE}/posts`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ title: titulo, body: cuerpo, userId }), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const post = await response.json(); mostrar("resultadoPost", "ok", `✅ Post creado (simulado por JSONPlaceholder)<br> <strong>ID asignado:</strong> ${post.id}<br> <div class="json-box">${JSON.stringify(post, null, 2)}</div>` ); } catch (error) { mostrar("resultadoPost", "err", `❌ Error: ${error.message}`); } finally { this.disabled = false; } }); // ── 2. PUT ──────────────────────────────────────────────────────────── document.getElementById("btnPut").addEventListener("click", async function() { const id = parseInt(document.getElementById("putId").value); const titulo = document.getElementById("putTitulo").value.trim(); if (!titulo) { mostrar("resultadoPut", "err", "❌ Escribí un nuevo título"); return; } this.disabled = true; mostrar("resultadoPut", "loading", `⏳ Enviando PUT al post #${id}...`); try { const response = await fetch(`${BASE}/posts/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id, title: titulo, body: "Contenido reemplazado", userId: 1 }), }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const post = await response.json(); mostrar("resultadoPut", "ok", `✅ Post #${id} actualizado<br> <div class="json-box">${JSON.stringify(post, null, 2)}</div>` ); } catch (error) { mostrar("resultadoPut", "err", `❌ Error: ${error.message}`); } finally { this.disabled = false; } }); // ── 3. DELETE ───────────────────────────────────────────────────────── document.getElementById("btnDelete").addEventListener("click", async function() { const id = parseInt(document.getElementById("deleteId").value); this.disabled = true; mostrar("resultadoDelete", "loading", `⏳ Enviando DELETE al post #${id}...`); try { const response = await fetch(`${BASE}/posts/${id}`, { method: "DELETE", }); if (!response.ok) throw new Error(`HTTP ${response.status}`); // DELETE exitoso devuelve status 200 con body vacío {} mostrar("resultadoDelete", "ok", `✅ Post #${id} eliminado — Status: ${response.status} ${response.statusText}<br> <small style="color:#555">JSONPlaceholder simula el borrado pero no persiste los cambios.</small>` ); } catch (error) { mostrar("resultadoDelete", "err", `❌ Error: ${error.message}`); } finally { this.disabled = false; } }); // ── 4. Probar errores HTTP ──────────────────────────────────────────── function agregarLog(mensaje, tipo) { const log = document.getElementById("logErrores"); const div = document.createElement("div"); div.className = tipo === "ok" ? "ok-log" : "err-log"; div.textContent = mensaje; log.insertBefore(div, log.firstChild); if (log.children.length > 8) log.lastChild.remove(); } // URL que devuelve 404 document.getElementById("btn404").addEventListener("click", async function() { this.disabled = true; agregarLog("⏳ Fetching /posts/99999...", "ok"); try { const res = await fetch(`${BASE}/posts/99999`); // fetch NO lanza error en 404 — hay que verificar res.ok if (!res.ok) { throw new Error(`HTTP ${res.status}: ${res.statusText}`); } const data = await res.json(); agregarLog(`✅ OK: ${JSON.stringify(data)}`, "ok"); } catch (error) { // El error viene de nuestro throw, no de fetch agregarLog(`❌ Capturado: ${error.message}`, "err"); } finally { this.disabled = false; } }); // URL inválida que causa error de red document.getElementById("btn500").addEventListener("click", async function() { this.disabled = true; agregarLog("⏳ Fetching URL inválida...", "ok"); try { // URL que falla a nivel de red (no HTTPS correcto) const res = await fetch("https://this-domain-does-not-exist-xyz.com/api"); agregarLog(`Status: ${res.status}`, "ok"); } catch (error) { // Aquí sí lanza fetch — error de red agregarLog(`❌ Error de red: ${error.message}`, "err"); } finally { this.disabled = false; } }); </script> </body> </html>