Las APIs desempeñan un papel fundamental en la vida cotidiana de los desarrolladores al proporcionar una vía eficiente y versátil para acceder y manipular datos en servidores web.
En este artículo, profundizaremos en el concepto de las peticiones HTTP, explorando sus componentes y su ejecución en diversos entornos de programación. Además, examinaremos detalladamente cómo estas solicitudes son transmitidas a través de una red, respaldando nuestros análisis con ejemplos claros y concisos.
¿Qué es una petición HTTP?
Una petición HTTP, también conocida como llamada HTTP, constituye la solicitud que un cliente, como un navegador web, envía a un servidor. Esta solicitud está compuesta por diversos elementos y debe seguir un formato estándar para que el servidor pueda interpretarla adecuadamente.
El formato de una solicitud HTTP, denominado mensaje HTTP, se describe extensamente en los documentos RFC (Request for Comments en inglés), en este caso el RFC 7230. Estos documentos detallan las especificaciones técnicas, estándares y protocolos relacionados con las comunicaciones HTTP.
Los mensajes HTTP se componen de tres elementos principales: la línea de solicitud, las cabeceras y el cuerpo. Estos componentes trabajan en conjunto para formar una solicitud completa y comprensible para el servidor, permitiendo a los clientes solicitar, crear, modificar o eliminar información de manera eficiente.
Componentes de una petición HTTP
Línea de solicitud
La primera línea del mensaje, que incluye:
- Método. La acción que queremos ejecutar. Por ejemplo
GET
es usado habitualmente para solicitar datos yPOST
para enviarlos. - URI. El path o la ubicación del recurso. Por ejemplo
/users
. - Versión. La versión del protocolo HTTP que vamos a usar. Por ejemplo,
HTTP/1.1
oHTTP/2
.
Estas tres parte, unidas, van a conformar la línea completa:
POST /post HTTP/1.1
Cabeceras
Las cabeceras son líneas de información adicional o metadatos enviados junto con la solicitud. Algunas cabeceras muy comunes (aunque hay muchas otras) son:
- Host. La única requerida y la más importante. Indica el nombre del servidor.
- Accept. Indica los tipos de formato que el cliente es capaz de entender en la respuesta, como HTML, JSON o XML.
- Content-Type. Indica el formato de los datos que se van a enviar en el cuerpo (en el siguiente epígrafe explicaremos lo que es el cuerpo). Esta cabecera sólo tiene sentido en las peticiones que envían datos, como
POST
,PUT
oPATCH
. - User-Agent. Normalmente indica el nombre y versión del cliente que se está usando, como por ejemplo:
curl/8.5.0
.
Para ilustrar estos conceptos, consideremos un ejemplo práctico de una solicitud HTTP con sus respectivas cabeceras:
Host: httpbin.org
Accept: application/json
Content-Type: application/json
User-Agent: curl/8.5.0
Este conjunto de cabeceras informa al servidor httpbin.org
de que se está utilizando cURL en la versión 8.5.0, y que se acepta una respuesta en formato JSON.
Cuerpo
Finalmente, el cuerpo de la petición se incluye únicamente en aquellos mensajes HTTP que desean enviar datos adicionales al servidor. Como mencionamos anteriormente, este componente se agrega en solicitudes que utilizan los métodos POST
, PUT
o PATCH
, permitiendo la transferencia de información adicional junto con la solicitud.
Ten en cuenta de que para definir el formato de los datos que envías, es necesario utilizar la cabecera Content-Type
.
Esta directiva le indica al servidor cómo debe interpretar la información en el cuerpo.
Por ejemplo, si estás enviando datos en formato JSON, la cabecera Content-Type
debería ser application/json;
mientras que si estás enviando un formulario HTML, debes utilizar application/x-www-form-urlencoded
.
Un ejemplo de cuerpo podría ser este:
{
"hello": "world"
}
Resumen
Uniendo los ejemplos expuestos anteriormente, vamos a executar una petición y a crear un mensaje HTTP real.
Para ello, usaremos cURL, un conocido cliente que permite hacer llamadas HTTP desde el terminal.
curl -X POST 'https://httpbin.org/post' \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data '{ "hello": "world" }'
Este comando cURL está enviando una solicitud POST
al path /post
en el servidor httpbin.org
, indicando que acepta respuestas en formato JSON y que está enviando datos en formato JSON.
El mensaje HTTP generado para el comando anterior sería algo así:
POST /post HTTP/1.1
Host: httpbin.org
Accept: application/json
Content-Type: application/json
{ "hello": "world" }
¿Cómo se transmite una petición HTTP?
Una vez que hemos formateado nuestro mensaje HTTP, ¿cómo lo transmitimos al servidor? A través de un socket TCP. Este proceso es esencial para entender cómo la información es enviada y recibida entre el cliente y el servidor en una red.
Por ejemplo, en Ruby, podemos ejecutar esto mediante el uso de sockets TCP:
require 'socket'
# Crear un socket TCP
client_socket = TCPSocket.new('httpbin.org', 443) # Puerto 443 para HTTPS
# Definir la solicitud HTTP
http_request = <<~HTTP_REQUEST
POST /post HTTP/1.1
Host: httpbin.org
Accept: application/json
Content-Type: application/json
{ "hello": "world" }
HTTP_REQUEST
# Enviar la solicitud al servidor
client_socket.puts http_request
# Manejar la respuesta del servidor
response = client_socket.read
puts "Respuesta del servidor:"
puts response
# Cerrar la conexión
client_socket.close
Simplificación con librerías
Generar mensajes HTTP y escribir código repetitivo cada vez que queremos hacer una solicitud a una API puede ser un proceso tedioso. Afortunadamente, existen bibliotecas que simplifican este proceso, tanto las integradas en los lenguajes como las externas que se pueden instalar.
Estas bibliotecas automatizan los detalles de bajo nivel y proporcionan una interfaz más intuitiva para interactuar con servicios web, agilizando así el desarrollo de aplicaciones que dependen de comunicaciones HTTP.
¿Cómo se hace una petición HTTP?
Vamos a reescribir nuestro ejemplo anterior en Ruby que utilizaba sockets a otros en diferentes lenguajes.
Javascript
const url = 'https://httpbin.org/post';
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
};
const data = { 'hello': 'world' };
fetch(url, {
method: 'POST',
headers: headers,
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
console.log(data);
});
Python
import requests
url = 'https://httpbin.org/post'
headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
}
data = {'hello': 'world'}
response = requests.post(url, json=data, headers=headers)
print(response.json())
PHP
$url = 'https://httpbin.org/post';
$headers = [
'Accept: application/json',
'Content-Type: application/json',
];
$data = [
'hello' => 'world',
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
echo $response;
curl_close($ch);
Ruby
require 'net/http'
require 'json'
url = URI.parse('https://httpbin.org/post')
headers = {
'Accept' => 'application/json',
'Content-Type' => 'application/json',
}
data = { 'hello' => 'world' }
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
request = Net::HTTP::Post.new(url.path, headers)
request.body = data.to_json
response = http.request(request)
puts JSON.parse(response.body)
Resumen
En este artículo hemos analizado proceso de creación de las peticiones HTTP, explorando cada una de sus partes y explicando la estructura fundamental de este protocolo. También nos sumergimos en el concepto del mensaje HTTP, desglosando sus elementos.
Además, hemos explicado cómo se envían las peticiones internamente a través de sockets TCP. Esta parte del proceso es fundamental para comprender cómo la información es enviada y recibida entre el cliente y el servidor en un entorno de red.
Para proporcionar una comprensión más completa, hemos incluido varios ejemplos prácticos en diferentes lenguajes, lo que permite visualizar cómo se implementan en la práctica.
En resumen, las peticiones HTTP son la columna vertebral de la comunicación en la web moderna, y comprender su funcionamiento es fundamental para cualquier desarrollador. Con este conocimiento y el apoyo de las herramientas adecuadas, podemos construir aplicaciones web robustas y eficientes que satisfagan las necesidades de nuestros usuarios.