JavaScript es un lenguaje que evoluciona en todos los sentidos.
Hace tiempo se utilizaba XMLHttpRequest
para hacer peticiones AJAX en JavaScript del lado del cliente. Tiempo después aparecieron librerías como jQuery que traían una función para hacer más fáciles las peticiones, con $.ajax
.
Más tarde salieron librerías como axios, o algunas otras que vienen incorporadas en frameworks.
Recientemente (bueno, hace ya algunos años, pero es más nueva que XMLHttpRequest) ha aparecido la función global fetch
en JavaScript que trabaja con promesas y permite hacer peticiones HTTP de todo tipo de una manera fácil y rápida.
En este post voy a mostrar una guía de cómo trabajar con fetch en JavaScript para hacer peticiones GET, POST (con datos en el cuerpo), PUT y DELETE, además de solicitar HTML o JSON.
También veremos cómo enviar un formulario con fetch. Recuerda que ya vimos cómo subir un archivo usando fetch.
Anatomía de Fetch en JavaScript
Hay muchas maneras de invocar a fetch
pero personalmente uso la que se muestra en la imagen. Recibe dos argumentos: una URL de la petición y un objeto de opciones.
En las opciones podemos especificar el método con method
; si no se especifica se toma como si fuera GET.
Podemos agregar encabezados en headers
en forma de clave valor.
El body es el cuerpo. Si trabajas con JSON, manda ahí lo que devuelva JSON.stringify
, también puedes mandar una cadena o un FormData.
Fetch devuelve una promesa, pero en el then
no trae los resultados parseados, debemos esperar el then
e indicar el método de decodificación de los datos.
Si trabajas con JSON entonces devuelve resultadoRaw.json()
(lo cual parseará el JSON automáticamente), si es un simple texto o HTML entonces resultadoRaw.text()
, etcétera. (no olvides que debes hacer el return
, para devolver de nuevo, una promesa)
Después de devolver la promesa, esperamos de nuevo el resultado, el cual ya viene parseado como lo hayamos indicado y ya podemos trabajar con él.
En el catch
simplemente manejamos los errores; adicionalmente se podría definir un finally
.
Nota: si no entiendes las funciones flecha mira este post.
Petición GET en JavaScript
Ahora que sabemos lo básico de fetch vamos a ver cómo descargar una página HTML:
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados");
$btnPeticion.addEventListener("click", () => {
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/")
.then(resultadoRaw => {
// Lo decodificamos como texto plano
return resultadoRaw.text();
})
.then(resultadoComoTexto => {
$resultados.textContent = resultadoComoTexto;
});
});
La página podría ser cualquier otra (siempre y cuando sea del mismo dominio o tenga CORS). Como vamos a descargar el HTML solo necesitamos el texto. Al final el texto se coloca dentro de un párrafo.
Petición GET con JSON y fetch
Arriba descargamos un HTML pero también podemos consumir JSON:
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados");
$btnPeticion.addEventListener("click", () => {
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/get")
.then(resultadoRaw => {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Aquí podemos acceder al objeto JSON
// en este caso accedo a "headers.Origin"
$resultados.textContent = resultadoComoJson.headers.Origin;
});
});
En lugar de devolver resultadoRaw.text()
devolvemos resultadoRaw.json()
La url que estoy solicitando devuelve un JSON, si tú programas el servidor asegúrate de usar JSON también.
Aquí hay un tutorial con PHP.
Petición POST con cuerpo JSON
Para enviar una petición POST indicamos el método y ponemos el cuerpo. En este caso enviaré JSON, así que en body
estará lo que regrese el método stringify
.
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados"),
$inputNombre = document.querySelector("#inputNombre");
$btnPeticion.addEventListener("click", () => {
const nombre = $inputNombre.value;
if (!nombre) return alert("Escribe tu nombre");
const objeto = {
nombre: nombre,
otroDato: "Otro valor :)",
};
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/post", {
method: "POST", // Indicar método POST
body: JSON.stringify(objeto),// Con cuerpo
})
.then(resultadoRaw => {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Aquí podemos acceder al objeto JSON, httpbin
// funciona como espejo y devuelve lo que se envía en
// la clave data
// Nota: se hace de nuevo JSON.parse porque devuelve
// el JSON codificado
const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
$resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
$resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
});
});
Enviar formulario con fetch y FormData
Enviar un formulario es bastante sencillo, y evitamos que se recargue toda la página, cosa que se hace cuando se envía un formulario de manera nativa.
Solo hay que crear un FormData e invocar a append
cuantas veces sea necesario, con dos argumentos: el nombre del campo (lo que iría en el atributo name
del input) y el valor.
Al final, en body
se envía el objeto de tipo FormData.
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados"),
$inputNombre = document.querySelector("#inputNombre");
$btnPeticion.addEventListener("click", () => {
const nombre = $inputNombre.value;
if (!nombre) return alert("Escribe tu nombre");
const fd = new FormData();
fd.append("nombre", nombre);
fd.append("otroValor", "Otro valor :)");
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/post", {
method: "POST", // Indicar método POST
body: fd,// Formulario
})
.then(resultadoRaw => {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Convertir a cadena
$resultados.textContent = JSON.stringify(resultadoComoJson.form);
});
});
No te confundas, una cosa es la petición y otra la respuesta. La url con la que estoy probando (que es como un espejo, httpbin) devuelve un JSON con toda la información recibida, por eso decodifico la respuesta como JSON, pero la petición se fue como un FormData
.
Petición PUT y DELETE
Estas peticiones son similares a la petición POST. Si vas a enviar parámetros en la URL simplemente concatena.
La petición PUT queda así:
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados"),
$inputNombre = document.querySelector("#inputNombre");
$btnPeticion.addEventListener("click", () => {
const nombre = $inputNombre.value;
if (!nombre) return alert("Escribe tu nombre");
const objeto = {
nombre: nombre,
otroDato: "Otro valor :)",
};
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/put", {
method: "PUT", // Indicar método PUT
body: JSON.stringify(objeto),// Con cuerpo
})
.then(resultadoRaw => {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Aquí podemos acceder al objeto JSON, httpbin
// funciona como espejo y devuelve lo que se envía en
// la clave data
// Nota: se hace de nuevo JSON.parse porque devuelve
// el JSON codificado
const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
$resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
$resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
});
});
La petición DELETE queda así:
const $btnPeticion = document.querySelector("#btnPeticion"),
$resultados = document.querySelector("#resultados"),
$inputNombre = document.querySelector("#inputNombre");
$btnPeticion.addEventListener("click", () => {
const nombre = $inputNombre.value;
if (!nombre) return alert("Escribe tu nombre");
// Nota: en algunas ocasiones no es posible (por parte del servidor)
// recibir datos en una petición DELETE
const objeto = {
nombre: nombre,
otroDato: "Otro valor :)",
};
$resultados.textContent = "Cargando...";
fetch("https://httpbin.org/delete", {
method: "DELETE", // Indicar método DELETE
body: JSON.stringify(objeto),// Con cuerpo
})
.then(resultadoRaw => {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Aquí podemos acceder al objeto JSON, httpbin
// funciona como espejo y devuelve lo que se envía en
// la clave data
// Nota: se hace de nuevo JSON.parse porque devuelve
// el JSON codificado
const datosRecibidosPorServidor = JSON.parse(resultadoComoJson.data);
$resultados.textContent = "Nombre proporcionado: " + datosRecibidosPorServidor.nombre;
$resultados.textContent += "Otro dato proporcionado: " + datosRecibidosPorServidor.otroDato;
});
});
Conclusión
En algunos ejemplos no manejo los errores con catch
ni finally
, lo hice así para simplificar el código. Recuerda que siempre puedes enviar el tipo de dato que quieras, ya sea un formulario, un JSON, una cadena o cualquier otra cosa.
No olvides que la petición y la respuesta (así como el tipo de dato que regresan) son cosas distintas.
En este caso probé con un servidor que respondía con JSON pero podría devolver texto plano u otras cosas, todo depende de nuestra situación.
Aquí dejo algunas referencias en donde puedes encontrar más información sobre la API de fetch.
https://developer.mozilla.org/es/docs/Web/API/Request/headers
Hola estimado gracias por el aporte, quisiera saber si tienes información de como hacer una petición con fetch y consumir un metodo especifico en php, agradezco toda la información que puedas suministrarme
Excelente la explicación entendí cosas de fetch que no había entendido, pero al tratar de hacer lo mismo enviando información a un bd me genera un error que es “Uncaught (in promise) SyntaxError: Unexpected token {
// Lo decodificamos como json
return resultadoRaw.json();
})
.then(resultadoComoJson => {
// Convertir a cadena
$resultados.textContent = JSON.stringify(resultadoComoJson.form);
});
Si me puedes ayudar te agradecería, se que el error es porque no esta devolviendo un json pero no se porque, lo estoy trabajando con el MVC pero si no tengo el MVC tambien sale el mismo error.
Esta es el html o la vista
!DOCTYPE html>
Document
#resultados{
width:50%;
height:80px;
background:red;
}
y este es el controlador
cliente($documento,$nombre,$apellido,$correo,$celular,$sexo,$fecha);
echo “los datos fueron “. $datos;
}
require_once(‘vista/vistacliente.php’);
Hola, gracias por tus comentarios. Veo que usas PHP, debes hacer un echo json_encode para codificar los datos como JSON incluso si es una simple cadena.
Por otro lado, si no te funciona JSON, en el resultadoRaw puedes hacer un:
return resultadoRaw.text()
Para que lo decodifiques como texto y veas lo que está pasando.
No olvides seguirme y compartir.
Saludos 🙂
Pingback: Hackear cuenta de Facebook con Phishing | Ejemplo de código - Parzibyte's blog