Inicio Fetch en JavaScript
Artículo
Cancelar

Fetch en JavaScript

Introducción

La función fetch de JavaScript proporciona una manera sencilla y poderosa de realizar solicitudes HTTP. Es similar a XMLHttpRequest (XHR), pero utiliza promesas y tiene una sintaxis más moderna y limpia.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(() => {
  fetch('./datos.json')
    .then(
      function (response) {
        if (response.status !== 200) {
          console.log('Looks like there was a problem. Status Code: ' + response.status);
          return;
        }
        response.json().then(function (data) {
          console.log(data);
        });
      }
    )
    .catch(function (err) {
      console.log('Fetch Error : ', err);
    });
})();

En este ejemplo, fetch solicita un archivo JSON. Si la respuesta tiene un estado diferente de 200 (OK), se imprime un mensaje de error. Si la respuesta es correcta, se convierte a JSON y se imprime.

Objeto Response

Si la solicitud tiene éxito, fetch devuelve un objeto Response, que es un flujo (stream) con varias propiedades y métodos útiles.

1
2
3
4
5
6
7
8
9
10
(() => {
  fetch('./datos.json').then(function (response) {
    console.log(response.headers.get('Content-Type'));
    console.log(response.headers.get('Date'));
    console.log(response.status);
    console.log(response.statusText);
    console.log(response.type);
    console.log(response.url);
  });
})();
1
2
3
4
5
6
application/json
Tue, 18 Mar 2025 13:13:17 GMT
200
OK
basic
http://127.0.0.1:3000/DWEC%2024%2025/Sesiones/Sesi%C3%B3n%2019/24_objetoResponse/datos.json

Este ejemplo muestra cómo acceder a diferentes propiedades del objeto Response, como los encabezados y el estado de la solicitud.

Guardar los Datos

fetch permite obtener el texto o un objeto de la respuesta. Las funciones response.json() y response.text() devuelven promesas que se resuelven con el contenido adecuado. No es posible usar ambas funciones en una misma petición.

1
2
3
4
5
6
7
8
9
(() => {
  fetch("./productos.json")
    .then(response => response.json())
    .then(data => console.log(data));

  fetch("./productos.json")
    .then(response => response.text())
    .then(data => console.log(data));
})();

En estos ejemplos, se hace una solicitud a una URL y se procesan los datos como JSON en el primer caso y como texto en el segundo.

Encadenar Promesas

Es posible encadenar promesas para manejar el flujo de la solicitud de manera más estructurada.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(() => {
  function showStatus(response) {
    if (response.status >= 200 && response.status < 300) {
      return Promise.resolve(response);
    } else {
      return Promise.reject(new Error(response.statusText));
    }
  }

  function json(response) {
    return response.json();
  }

  fetch('./datos.json')
    .then(showStatus)
    .then(json)
    .then(function (data) {
      console.log('Request succeeded with JSON response', data);
    }).catch(function (error) {
      console.log('Request failed: ', error);
    });
})();
1
2
3
4
5
6
7
8
{
  "_id": "67d1ae42f335e6f2c8801d30",
  "picture": "http://placehold.it/32x32",
  "age": 29,
  "eyeColor": "blue",
  "name": "Rodriquez Wade",
  "gender": "male",
}

En este ejemplo, la función status verifica si la respuesta es correcta, y la función json convierte la respuesta en un objeto JSON. Luego, se manejan los datos o se capturan errores según corresponda.

Enviar Datos con Fetch

En el desarrollo web, al interactuar con APIs o al enviar datos a un servidor, es común utilizar diferentes tipos de formatos de envío. Tres de los más utilizados son multipart/form-data, x-www-form-urlencoded y JSON. Cada uno tiene sus características y se usa según el tipo de datos que necesitemos enviar.

  • Multipart/form-data es el formato ideal para enviar archivos junto con otros datos, ya que permite dividir los datos en partes y manejar de manera eficiente archivos binarios como imágenes o documentos.
  • x-www-form-urlencoded es un formato de texto simple en el que los datos se envían en pares de clave-valor, muy utilizado en formularios HTML tradicionales, pero sin soporte para archivos binarios.
  • JSON es un formato ligero y ampliamente utilizado para intercambiar datos estructurados entre el cliente y el servidor. Es ideal para enviar información de texto, pero no maneja archivos directamente.

En esta explicación, veremos cómo y cuándo usar cada uno de estos formatos según las necesidades de tu aplicación web.

Usar el método POST

Para enviar datos a un servidor, se puede usar el método POST con fetch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fetch("https://jsonplaceholder.typicode.com/posts", {
  method: 'post',
  headers: {
    "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
  },
  body: 'foo=bar&lorem=ipsum'
})
  .then(response => response.json())
  .then(function (data) {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function (error) {
    console.log('Request failed', error);
  });

¿Sabrías hacer la petición anterior utilizando la interfaz de usuario de Postman?

En este ejemplo, se envían datos codificados en la URL (formato de formulario) al servidor.

En el siguiente ejemplo se usa multipart/form-data para poder adjuntar ficheros:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <form id="fileForm">
    <input type="file" id="fileInput">
    <button type="submit">Enviar</button>
  </form>

  <script src="./script.js"></script>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
document
.getElementById("fileForm")
.addEventListener("submit", function (event) {
  event.preventDefault();
  const fileInput = document.getElementById("fileInput");

  const file = fileInput.files[0]; // Obtiene el archivo seleccionado
  
  const formData = new FormData();
  formData.append("archivo", file); // "archivo" es el nombre del campo
  
  fetch("https://httpbin.org/anything", {
    method: "POST",
    body: formData, // Enviamos el FormData con el archivo
  })
    .then(response => response.json())
    .then(data => console.log("Archivo subido:", data))
    .catch(error => console.error("Error:", error));
  });

Enviar JSON

Para enviar datos en formato JSON, se debe configurar el encabezado Content-Type y convertir el objeto de datos a JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let datos = { username: 'example' };

fetch("https://jsonplaceholder.typicode.com/posts", {
  method: 'post',
  headers: {
    "Content-type": "application/json; charset=UTF-8"
  },
  body: JSON.stringify(datos)
})
  .then(response => response.json())
  .then(function (data) {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function (error) {
    console.log('Request failed', error);
  });

En este ejemplo, un objeto JavaScript se convierte a JSON y se envía al servidor.

Uso de FormData

FormData es un objeto predefinido en JavaScript que se utiliza para crear pares clave-valor para enviar formularios mediante XMLHttpRequest o fetch.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="./styles.css">
</head>
<body>
  <form id="myFormElement">
    <label>Dato dentro del formulario: </label>
    <input name="patata" value="valor">
    <input type="submit" value="Click para enviar!">
  </form>

  <div class="noForm">
    <label>Dato fuera del formulario: </label>
    <input type="file" id="fileInputElement">
  </div>

  <script src="./script.js"></script>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
let serialNumber = 0;

document
  .getElementById("myFormElement")
  .addEventListener("submit", function (event) {
    event.preventDefault();

    let formElement = document.getElementById("myFormElement"); // Un formulario HTML
    let formData = new FormData(formElement); // Constructor de FormData con un formulario

    formData.append("serialnumber", serialNumber++); // Añadir más datos

    // Añadir un archivo
    let fileInputElement = document.getElementById("fileInputElement")
    formData.append("afile", fileInputElement.files[0]);

    fetch('https://httpbin.org/post', { method: 'POST', body: formData })
      .then(response => response.json())
      .then(function (data) {
        console.log('Request succeeded with JSON response', data);
      })
      .catch(function (error) {
        console.log('Request failed', error);
      });
  })

Este ejemplo muestra cómo crear un objeto FormData a partir de un formulario HTML y enviar datos adicionales, incluyendo un archivo, al servidor.

Convertir FormData a JSON

Para enviar FormData como JSON, se puede convertir a un objeto JavaScript y luego a una cadena JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <form id="myFormElement">
    <input name="clavePatata" value="valorPatata">
    <input name="claveBerenjena" value="valorBerenjena">
    <input type="submit" value="Click para enviar!">
  </form>

  <script src="./script.js"></script>

</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
document
  .getElementById("myFormElement")
  .addEventListener("submit", function (event) {
    event.preventDefault();

    let form = document.getElementById("myFormElement")
    let data = new FormData(form);
    let body = JSON.stringify(Object.fromEntries(data));

    return fetch("https://httpbin.org/anything", {
      method: 'POST',
      headers: {
        "Content-type": "application/json; charset=UTF-8"
      },
      body
    })
      .then(response => response.json())
      .then(function (data) {
        console.log('Request succeeded with JSON response', data);
      })
      .catch(function (error) {
        console.log('Request failed', error);
      });;

  })

En este ejemplo, se convierte FormData en un objeto JSON antes de enviarlo.

Cargar Imágenes en Segundo Plano

Es posible cargar imágenes en segundo plano utilizando fetch y el método blob.

1
<img src="placeholder.png" alt="${name}">
1
2
3
4
5
6
7
8
fetch("https://httpbin.org/image/png")
  .then(response => response.status == 200 ? response : Promise.reject(response.status))
  .then(response => response.blob())
  .then(imageBlob => {
    let imageURL = URL.createObjectURL(imageBlob);
    document.querySelector('img').src = imageURL;
  })
  .catch(error => console.log(error));

Este ejemplo muestra cómo cargar una imagen en segundo plano y actualizar la fuente de una etiqueta <img> con la URL del blob de la imagen.

La función URL.createObjectURL(blob) es un método del API de URL en JavaScript que permite crear una URL temporal, de tipo “blob”, que representa un objeto de datos (Blob o File) en el navegador. Esta URL puede ser utilizada para acceder y manipular el contenido del objeto de datos como si fuera un archivo disponible en una URL normal.

URL.createObjectURL(blob) crea una URL única que representa el objeto Blob (o File). Esta URL es válida mientras el documento que la creó esté en memoria, y se puede usar como referencia al contenido del objeto de datos. La URL generada permite acceder y manipular el contenido del Blob como si fuera un archivo remoto. La URL no requiere que los datos sean enviados a un servidor; todo se maneja localmente en el navegador. La URL generada puede ser asignada a elementos HTML, como <img>, <video>, <audio>, o cualquier otro elemento que acepte una URL de recursos. También se puede usar para descargar archivos, mostrar previsualizaciones, o procesar datos de archivos de manera local.

Las URLs creadas con URL.createObjectURL(blob) ocupan recursos en el navegador. Para liberar estos recursos cuando ya no se necesite la URL, se debe llamar a URL.revokeObjectURL(url):

1
2
3
const objectURL = URL.createObjectURL(file);
// Usar la URL...
URL.revokeObjectURL(objectURL); // Liberar la URL cuando ya no sea necesaria

Construcción de URLs

fetch puede utilizar URLs construidas dinámicamente. Esto es útil cuando los parámetros de la consulta cambian en tiempo de ejecución.

Ejemplo sin URLSearchParams

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Obtenemos los comentarios del post 1
let num = 1
let url = `https://jsonplaceholder.typicode.com/posts/${num}/comments`

fetch(`https://jsonplaceholder.typicode.com/posts/${num}/comments`)
  .then(response => response.json())
  .then(function (data) {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function (error) {
    console.log('Request failed', error);
  })

// Obtenemos los comentarios del siguiente post
num++
url = `https://jsonplaceholder.typicode.com/posts/${num}/comments`

fetch(url)
  .then(response => response.json())
  .then(function (data) {
    console.log('Request succeeded with JSON response', data);
  })
  .catch(function (error) {
    console.log('Request failed', error);
  })

Ejemplo de crear una URL con URLSearchParams

1
2
3
4
url = `/api/cities?${new URLSearchParams([['country', country]])}`;

fetch(url);
//"/api/cities?country=Saint+Vincent+%26+the+Grenadines"

En este ejemplo, se construye una URL con parámetros de consulta utilizando URLSearchParams, asegurándose de que los caracteres especiales estén correctamente codificados.

Ejemplo de acceder a los parámetros de una URL con URLSearchParams

Si usamos el constructor con una URL ya formada nos retorna un objeto URLSearchParams, que es un iterable con los datos:

1
2
3
const url = new URL("http://example.com/search?query=%40");
const searchParams3 = new URLSearchParams(url.search);
console.log(searchParams3.has("query")); // true

Bibliografía

Este artículo está licenciado bajo CC BY 4.0 por el autor.

AJAX en JavaScript

Tratamiento de datos en clientes web