Peticiones GET y POST nativas en NodeJS sin dependencias

Cuando estamos trabajando en un proyecto de NodeJS que va a consumir una API tenemos el impulso de instalar la dependencia Axios o similar. Pero, ¿sabías que puedes hacer peticiones web con NodeJS sin librerías externas? Lo vemos en este artículo con ejemplos.
Peticiones GET y POST nativas en NodeJS sin dependencias

En la mayoría de los proyectos, sea cual sea el fin y el lenguaje del mismo, nuestro código tiene que hacer peticiones web a otros sistemas como, por ejemplo, consultar una API centralizada o enviar una petición a otro servicio.

Existen multitud de librerías y complementos con las que resulta más fácil hacer estas peticiones. En NodeJS tuvimos request, una librería que simplificaba hacer peticiones web a otros sistema. Sin embargo, desde febrero de 2020, esta utilidad ha sido marcada como abandonada (por lo que no deberíamos usarla de ninguna forma cuando estemos empezando un nuevo proyecto). Desde entonces, otras librerías han recibido con los brazos abiertos a los usuarios que usaban request: axios (tal vez una de las librerías más usadas en el entorno Javascript en el servidor), node-fetch o Got. Estas librerías facilitan la tarea de hacer peticiones web a través de la red, GET, POST y los nuevos métodos HTTP.

Generalmente, cuando algo se puede hacer en NodeJS pero requiere mucho esfuerzo o muchas líneas de código, no dudamos en utilizar las librerías de terceros y gratuitas de NPM. Y no es una mala decisión: si alguien ha simplificado la tarea de hacer algo en un par de líneas de código, ¿por qué intentar reinventar la rueda? Este es el caso que más veces me he encontrado en NodeJS: hacer peticiones web es lo mismo que decir “Voy a instalar Axios”.

El otro día estaba programando una librería para Javascript que permitiese enviar notificaciones de forma sencilla a Google Chat y claro, instalé como dependencia Axios. Al poco tiempo, la usé en un proyecto que tenía en marcha y me di cuenta de que la propia librería tenía más dependencias que el proyecto en sí y esto me hizo replantearme la cuestión: ¿realmente necesito Axios como dependencia de mi sencilla librería?

Pues mi conclusión fue la siguiente: una librería sencilla debería tener la menor cantidad de dependencias posibles. Esto es así por dos motivos, el primero, que conlleva menos trabajo mantenerlas y, en segundo lugar, porque las haces más independientes. En concreto, esta librería lo único que hace es un petición POST a Google Chat. No necesitaba una librería para hacer una simple llamada POST.

La ventaja principal de Axios son los interceptares. Así que si no sabes lo que son, tienes todas las papeletas para que realmente no lo necesites.

Peticiones POST en NodeJS sin dependencias

Con la intención de dejar mi librería sin dependencias externas, me convencí a mi mismo de no emplear Axios. Pero, ¿cómo demonios hago una petición POST en NodeJS nativo? Pues la respuesta es tremendamente sencilla: usando el siguiente código.

const https = require("https");

send(message) {
  // Pasamos a String el mensaje JSON que recibimos.
  const json = JSON.stringify(message);

  // Configuramos los parámetros de la petición
  const requestOptions: RequestOptions = {
    protocol: 'https:',
    port: 443,
    hostname: "google.com",
    path: "/page.php?a=1",
    method: 'POST',
    headers: {
    'Content-Type': 'application/json'
    }
  }

  return new Promise((resolve, reject) => {
    //Creamos una nueva promesa que envuelva la petición
    const request = https.request(requestOptions, (res) => {
      let data = ''
      //Cada vez que recibamos un dato, lo añadimos a la variable data
      res.on('data', (chunk:string) => {
        data += chunk
      });

          // Este evento se detona cuando finaliza la transmisión
          //   todo el cuerpo de la petición ya está en "data"
      res.on('end', () => {
        const json = JSON.parse(data);
        if (res.statusCode && (res.statusCode >= 200 && res.statusCode <= 299)) {
          resolve(json);
        } else {
          reject(json);
        }
      });
    // Si hubiese un error de conexión, detonará este evento. 
    }).on('error', (error: Error) => {
      console.error(error);
      return reject(error);
    });

  //PARTE CLAVE. Añadir los datos al cuerpo y COMENZAR la petición
  request.write(json);
  request.end();
  });

}

Este código puede parecer un mazacote comparado con la simple línea que es hacer la petición en Axios, pero te estás ahorrando importar una dependencia. Además, puedes envolverla en una función y usarla cuantas veces necesites.

En NodeJS deberías estar acostumbrado a que todo son eventos y en el código anterior hay tres listeners. El primero, on.error(..., es un listener que se encarga de ejecutar código cuando falla la petición; es decir, cuando falle la capa de red. Los otros dos res.on('data') y res.on('end') se detona cuando llega la respuesta con datos y cuando la respuesta ha sido entregada por completo, respectivamente.

De esta forma puedes hacer una petición POST nativa en NodeJS sin usar ninguna dependencia externa. Esto significa que tu código no depende de otra librería externa, por lo que no deberías tener que estar tan pendiente de si Axios cambia o no, pues tu código solo depende del propio motor de NodeJS.

Cómo hacer una petición GET en NodeJS nativa y sin dependencias

En el código anterior hicimos una petición POST de forma nativa en NodeJS sin la necesidad de incluir librerías de terceros como Axios. Pero, ¿y si lo que yo necesito es una petición GET? Pues la respuesta es tremendamente sencilla. El código anterior te sigue valiendo, lo único que tienes que hacer es:

  • Cambiar el método HTTP que se va a usar en la petición. Es decir, en requestOptions.method establecemos GET.
  • Por definición, las peticiones GET no tienen cuerpo de petición, así que retiramos del código anterior la línea request.write(json);. Esto hará que la petición GET no tenga cuerpo.

Con estos dos simples cambios, el mismo código de la petición POST que vimos antes ya te sirve para hacer peticiones GET (y cualquiera de los métodos HTTP que existen). Sin embargo, los programadores de NodeJS sabían que la mayor parte de peticiones que se hacen en Internet son del tipo GET, por ello, incluyeron un atajo que simplifica aún más el código necesario para hacer una petición GET con NodeJS.


const http = require("http")

//Por sencillez, retiramos el wrapper de la promesa.
http.get("https://www.mydirection.com", res => {
  let data = ""

  res.on("data", d => {
    data += d
  })
  res.on("end", () => {
    console.log(data)
    //Llamar a un Callback o resolver la promera aquí.
  })
})

Así que, ya sea con el código completo o con el código shorthand, ya sabes como hacer peticiones GET en NodeJS sin ningún tipo de dependencia.

Pero... ¿y si la dirección es http (no segura)?

La mayoría de direcciones a las que podremos hacer peticiones GET o POST son servicios de otras empresas que siempre usan direcciones web seguras: protocolo HTTPS y, como le digo a los usuarios menos técnicos, con el candadito. Es por eso que hemos incluido en el código, en la primera línea, la llamada al módulo https de NodeJS.

Pero también es verdad que, mientras estamos programando en nuestro ordenador o en un entorno de desarrollo, es posible que no tengamos un certificado TLS válido y tengamos que usar direcciones HTTP (sin certificado y sin el famoso candidato). Aquí el módulo https de NodeJS no nos va a ayudar, pero si su hermano gemelo: http.

Este módulo http es exactamente igual que https en la forma de funcionar y en las funciones que expone. Ambos utilizan las mismas llamadas de cara al desarrollador, la diferencia es que https gestiona la complejidad de la gestión de las conexiones seguras, pero sin que el desarrollador tenga que hacer nada.

En cualquier caso, si sospechamos que vamos a hacer llamadas a http en nuestro código de NodeJS, tendremos que determinar si la ruta es https o no, e importar un módulo u otro en tiempo de ejecución.

const https = require('https');
const http = require('http');

const client = url.startsWith('http://')
   ? http : https;

client.get(.....);

Conclusión

Si estás haciendo un proyecto en NodeJS con muchísimas librerías como dependencia o que tiene una criticidad máxima, te recomiendo utilizar Axios o cualquier otra librería. Total, por una más.

Pero si estamos programando una librería (que es una aplicación pensada para ser siempre un complemento de otro programa más grande), deberíamos ser lo más prácticos posibles y no obligar al usuario a instalar más y más dependecias. De esta forma, mantenemos nuestro código más independiente y menos propenso a fallar con las sucesivas actualizaciones. Tan solo deberemos tener cuidado cuando NodeJS cambie su versión.

Espero haberte convencido para que pruebes a hacer peticiones web, GET o POST en tu próximo proyecto sin utilizar dependencias externas y hacerlas de forma nativa.

¡Qué tengas un feliz Coding!