> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/dariomaranes/intro-web-2025/llms.txt
> Use this file to discover all available pages before exploring further.

# Manejo de Respuestas

> Aprende a procesar respuestas HTTP de la Fetch API

# Manejo de Respuestas HTTP

Cuando haces una petición con `fetch()`, recibes un objeto **Response**. Este objeto contiene información sobre la respuesta del servidor y métodos para procesar los datos.

## El Objeto Response

```javascript theme={null}
const response = await fetch('https://api.ejemplo.com/datos');

console.log(response.status);     // 200, 404, 500, etc.
console.log(response.statusText); // "OK", "Not Found", etc.
console.log(response.ok);         // true si status es 200-299
console.log(response.headers);    // Headers del servidor
console.log(response.url);        // URL final (después de redirects)
```

### Propiedades Importantes

<AccordionGroup>
  <Accordion title="response.ok">
    Boolean que indica si la respuesta fue exitosa (status 200-299).

    ```javascript theme={null}
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    ```

    Es la forma más simple de verificar si hubo un error.
  </Accordion>

  <Accordion title="response.status">
    Código de estado HTTP numérico.

    ```javascript theme={null}
    if (response.status === 404) {
      console.log('Recurso no encontrado');
    } else if (response.status === 500) {
      console.log('Error del servidor');
    }
    ```
  </Accordion>

  <Accordion title="response.statusText">
    Mensaje de texto asociado al código de estado.

    ```javascript theme={null}
    console.log(response.statusText); // "OK", "Not Found", etc.
    ```
  </Accordion>

  <Accordion title="response.headers">
    Objeto Headers con las cabeceras de respuesta.

    ```javascript theme={null}
    const contentType = response.headers.get('Content-Type');
    console.log(contentType); // "application/json"
    ```
  </Accordion>
</AccordionGroup>

## Procesar el Cuerpo de la Respuesta

El cuerpo de la respuesta debe ser procesado con uno de estos métodos:

### response.json()

Parsea el cuerpo como JSON. Retorna una Promise.

```javascript theme={null}
async function cargarUsuarios() {
  try {
    var response = await fetch(url);
    if (!response.ok) {
      throw new Error("HTTP status " + response.status);
    }
    var data = await response.json();
    console.log("Users (async/await):", data);
    printUsers(data);
  } catch (error) {
    console.log(error);
    usersOutput.textContent = error;
  }
}
```

<Warning>
  Si el cuerpo no es JSON válido, `response.json()` lanzará un error. Asegúrate de que el Content-Type sea `application/json`.
</Warning>

### response.text()

Obtiene el cuerpo como texto plano:

```javascript theme={null}
const response = await fetch('/archivo.txt');
const texto = await response.text();
console.log(texto);
```

### response.blob()

Para archivos binarios (imágenes, PDFs, etc.):

```javascript theme={null}
const response = await fetch('/imagen.jpg');
const blob = await response.blob();

// Crear una URL para mostrar la imagen
const imageUrl = URL.createObjectURL(blob);
const img = document.createElement('img');
img.src = imageUrl;
document.body.appendChild(img);
```

### response.arrayBuffer()

Para datos binarios en bruto:

```javascript theme={null}
const response = await fetch('/datos.bin');
const buffer = await response.arrayBuffer();
```

### response.formData()

Para datos de formulario:

```javascript theme={null}
const response = await fetch('/formulario');
const formData = await response.formData();
```

<Note>
  Cada uno de estos métodos puede llamarse solo UNA vez. El cuerpo de la respuesta es un stream que se consume.
</Note>

## Verificar Códigos de Estado

### Manejo Básico con response.ok

```javascript theme={null}
const response = await fetch(url);

if (!response.ok) {
  throw new Error(`HTTP status ${response.status}`);
}

const data = await response.json();
```

### Manejo Específico por Código

```javascript theme={null}
const response = await fetch(url);

switch (response.status) {
  case 200:
    const data = await response.json();
    console.log('Datos recibidos:', data);
    break;
    
  case 404:
    console.error('Recurso no encontrado');
    break;
    
  case 401:
    console.error('No autorizado - inicia sesión');
    break;
    
  case 500:
    console.error('Error del servidor');
    break;
    
  default:
    console.error(`Error HTTP ${response.status}`);
}
```

## Ejemplo Completo: Verificación de Respuesta

```javascript theme={null}
function cargarUsuariosThen() {
  usersOutput.textContent = "Cargando...";
  fetch(url)
    .then(function (response) {
      // Verificar si la respuesta es exitosa
      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }
      // Parsear JSON
      return response.json();
    })
    .then(function (data) {
      console.log("Users (.then):", data);
      printUsers(data);
    })
    .catch(function (error) {
      console.log(error);
      usersOutput.textContent = error;
    });
}
```

## Manejar Errores de Red

Fetch rechaza la Promise solo en errores de red (sin conexión, DNS falla, etc.), NO en errores HTTP:

```javascript theme={null}
try {
  const response = await fetch(url);
  
  // Esto NO se ejecutará en un 404 o 500
  // Solo se ejecuta en errores de red
  
  if (!response.ok) {
    throw new Error(`HTTP error ${response.status}`);
  }
  
  const data = await response.json();
  
} catch (error) {
  // Maneja errores de red Y errores HTTP que lanzaste
  console.error('Error:', error);
}
```

<Tip>
  Por eso es crucial verificar `response.ok` - los errores HTTP no lanzan excepciones automáticamente.
</Tip>

## Leer Headers de Respuesta

```javascript theme={null}
const response = await fetch(url);

// Obtener un header específico
const contentType = response.headers.get('Content-Type');
console.log('Content-Type:', contentType);

// Verificar si existe un header
if (response.headers.has('X-Custom-Header')) {
  console.log('Header personalizado presente');
}

// Iterar sobre todos los headers
for (const [key, value] of response.headers) {
  console.log(`${key}: ${value}`);
}
```

## Timeout y Abortar Peticiones

### Usando AbortController

```javascript theme={null}
const controller = new AbortController();
const signal = controller.signal;

// Abortar después de 5 segundos
setTimeout(() => controller.abort(), 5000);

try {
  const response = await fetch(url, { signal });
  const data = await response.json();
  console.log(data);
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Petición abortada por timeout');
  } else {
    console.error('Error:', error);
  }
}
```

### Función Helper con Timeout

```javascript theme={null}
function fetchConTimeout(url, timeout = 5000) {
  return new Promise((resolve, reject) => {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => {
      controller.abort();
      reject(new Error('Timeout'));
    }, timeout);
    
    fetch(url, { signal: controller.signal })
      .then(response => {
        clearTimeout(timeoutId);
        resolve(response);
      })
      .catch(error => {
        clearTimeout(timeoutId);
        reject(error);
      });
  });
}

// Uso
try {
  const response = await fetchConTimeout('/api/data', 3000);
  const data = await response.json();
} catch (error) {
  console.error('Error o timeout:', error);
}
```

## Respuestas con Diferentes Content-Types

<Tabs>
  <Tab title="JSON">
    ```javascript theme={null}
    const response = await fetch(url);
    const data = await response.json();
    console.log(data);
    ```
  </Tab>

  <Tab title="HTML">
    ```javascript theme={null}
    const response = await fetch('/pagina.html');
    const html = await response.text();
    document.getElementById('contenedor').innerHTML = html;
    ```
  </Tab>

  <Tab title="Imagen">
    ```javascript theme={null}
    const response = await fetch('/imagen.jpg');
    const blob = await response.blob();
    const imageUrl = URL.createObjectURL(blob);

    const img = document.createElement('img');
    img.src = imageUrl;
    document.body.appendChild(img);
    ```
  </Tab>

  <Tab title="CSV">
    ```javascript theme={null}
    const response = await fetch('/datos.csv');
    const texto = await response.text();

    // Procesar CSV
    const lineas = texto.split('\n');
    const datos = lineas.map(linea => linea.split(','));
    console.log(datos);
    ```
  </Tab>
</Tabs>

## Buenas Prácticas

<Steps>
  <Step title="Siempre verifica response.ok">
    ```javascript theme={null}
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    ```
  </Step>

  <Step title="Maneja errores apropiadamente">
    ```javascript theme={null}
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(response.status);
      const data = await response.json();
    } catch (error) {
      console.error('Error:', error);
      // Mostrar mensaje al usuario
    }
    ```
  </Step>

  <Step title="Verifica el Content-Type">
    ```javascript theme={null}
    const contentType = response.headers.get('Content-Type');
    if (contentType && contentType.includes('application/json')) {
      const data = await response.json();
    } else {
      const text = await response.text();
    }
    ```
  </Step>

  <Step title="Proporciona feedback al usuario">
    ```javascript theme={null}
    mostrarCargando();
    try {
      const data = await fetch(url).then(r => r.json());
      mostrarDatos(data);
    } catch (error) {
      mostrarError(error);
    } finally {
      ocultarCargando();
    }
    ```
  </Step>
</Steps>

## Próximos Pasos

<CardGroup cols={2}>
  <Card title="localStorage" icon="database" href="/storage/local-storage">
    Guarda datos en el navegador permanentemente
  </Card>

  <Card title="Ejemplos de Fetch" icon="code" href="/examples/fetch-examples">
    Ve ejemplos completos de uso de Fetch
  </Card>
</CardGroup>
