Qué es una API y en qué consiste extraer datos de ella
API (Application Programming Interface) — es la interfaz a través de la cual un programa se comunica con otro y obtiene datos o ejecuta acciones sin conocer su funcionamiento interno. En la práctica, «trabajar con una API» significa casi siempre consumir una API web sobre el protocolo HTTP: el cliente envía una petición a una dirección concreta (el endpoint) y el servidor devuelve una respuesta.
Cuando hablamos de extraer datos vía API nos referimos al ciclo completo de obtención y parseo de los datos de un servicio externo:
- Construir y enviar una petición HTTP correcta.
- Recibir la respuesta del servidor.
- Comprobar el código de estado y las cabeceras.
- Parsear el cuerpo de la respuesta (casi siempre JSON) y convertirlo en objetos del programa.
- Gestionar los errores, los reintentos y la paginación.
Véase también: el artículo «Parseo de JSON» se centra en el paso concreto de parsear los datos, es decir, en convertir una cadena JSON en objetos. El presente artículo cubre el proceso completo de trabajo con una API, del que ese parseo es solo una parte.
A diferencia del web scraping de HTML, el trabajo con una API se apoya en respuestas estructuradas en un formato legible por máquina; por eso es más fiable, más estable y casi siempre preferible cuando el servicio dispone de una API oficial.
Anatomía de una petición HTTP
Toda petición a una API web se compone de varias partes.
Método (verbo HTTP)
El método describe la intención de la petición:
- GET — obtener datos (no modifica el estado).
- POST — crear un recurso nuevo o enviar datos.
- PUT / PATCH — actualizar un recurso (por completo / parcialmente).
- DELETE — eliminar un recurso.
URL y parámetros de consulta
La dirección del endpoint puede incluir parámetros de consulta para filtrar, ordenar y paginar:
https://api.example.com/users?role=admin&page=2&limit=50Cabeceras (headers)
Las cabeceras transportan los metadatos de la petición. Las más importantes al trabajar con una API:
Authorization— datos de autenticación (token, clave).Content-Type— formato del cuerpo que se envía (por ejemplo,application/json).Accept— formato en el que el cliente desea recibir la respuesta.User-Agent— identificador del cliente.
Cuerpo de la petición (body)
En POST/PUT/PATCH los datos viajan en el cuerpo, por regla general como una cadena JSON que antes hay que serializar a partir de los objetos del programa.
Anatomía de la respuesta y su parseo
La respuesta del servidor consta de un código de estado, cabeceras y cuerpo.
Códigos de estado
Antes de parsear el cuerpo hay que comprobar el código de estado:
- 2xx — éxito (
200 OK,201 Created,204 No Content). - 3xx — redirección.
- 4xx — error del lado del cliente (
400petición incorrecta,401no autenticado,403prohibido,404no encontrado,429demasiadas peticiones). - 5xx — error del lado del servidor.
Solo tiene sentido parsear el cuerpo como datos válidos con códigos 2xx. Aun así, el cuerpo de un error también suele contener un JSON útil con la descripción del problema.
Cabeceras de la respuesta
De las cabeceras de la respuesta se extrae información importante: Content-Type (formato del cuerpo), parámetros de paginación, límites de peticiones (X-RateLimit-Remaining) y directivas de caché.
Cuerpo de la respuesta
El cuerpo son los datos en sí. En la mayoría de las APIs es JSON, que hay que parsear (véase «Parseo de JSON»). Con menor frecuencia aparecen otros formatos de texto — XML (véase «Parseo de XML») y CSV (véase «Parseo de CSV») —, además de formatos binarios.
Autenticación y autorización
La mayoría de las APIs exigen demostrar que el cliente tiene derecho de acceso. Los métodos más extendidos:
- Clave de API — una cadena simple que se envía en una cabecera o en un parámetro de la petición.
- Token Bearer / OAuth 2.0 — un token en la cabecera
Authorization: Bearer <token>; el enfoque más habitual en las APIs modernas. - Basic Auth — usuario y contraseña en forma codificada.
- HMAC / firma de la petición — la petición se firma con un secreto; se emplea en APIs de pagos y de la nube.
Importante: las claves y los tokens son secretos. No deben guardarse en el código ni subirse al repositorio; utilice variables de entorno o almacenes protegidos.
Dificultades al trabajar con una API
La extracción de datos vía API rara vez se reduce a una sola petición. Estas son las dificultades típicas para las que conviene prepararse.
Paginación
Una API casi nunca entrega las colecciones grandes de una vez: los datos se dividen en páginas. Los modelos principales:
- Offset/limit —
?page=2&limit=50o?offset=100&limit=50. - Por cursor (cursor) — la respuesta incluye un puntero a la página siguiente (
next_cursor) que se envía en la petición siguiente. - Keyset — la página siguiente se solicita a partir del valor del último elemento (por ejemplo, su
ido su fecha).
Para reunir todos los datos hace falta un bucle que recorra las páginas hasta agotarlas.
Límite de frecuencia de peticiones (rate limiting)
Los servicios limitan el número de peticiones por periodo. Al superarlo llega el código 429. La solución correcta es vigilar las cabeceras de límites y aplicar una espera exponencial (backoff) con reintentos.
Redes poco fiables y reintentos
Las peticiones de red pueden fallar por timeout o por errores temporales 5xx. Para ganar robustez se aplican:
- timeouts razonables;
- reintentos (retry) para peticiones idempotentes, con esperas crecientes;
- el patrón circuit breaker ante fallos sistemáticos.
Datos cambiantes y validación
La respuesta de una API puede llegar incompleta, con campos null o con la estructura alterada tras una actualización de versión. Nunca conviene fiarse a ciegas de la estructura de la respuesta: hay que comprobar los campos y validar los datos.
Versionado
Las APIs evolucionan y sus versiones cambian (/v1/, /v2/). Conviene fijar una versión concreta y seguir los avisos de obsolescencia (deprecation).
Anidación y formatos diversos
Los datos útiles suelen estar escondidos en lo profundo de una estructura anidada (data.items[0].attributes.name). A veces, en lugar de JSON llega XML (véase «Parseo de XML») o CSV (véase «Parseo de CSV»), lo que exige otro parser.
Ejemplos de implementación en varios lenguajes
A continuación, ejemplos mínimos del ciclo completo: petición a la API, comprobación del estado y parseo de la respuesta JSON. Por uniformidad se usa el endpoint ficticio https://api.example.com/users/42.
Python
La popular biblioteca requests se encarga tanto de la petición como del parseo del JSON.
import requests
url = "https://api.example.com/users/42"
headers = {"Authorization": "Bearer YOUR_TOKEN"}
response = requests.get(url, headers=headers, timeout=10)
# Comprobación del estado
response.raise_for_status() # lanza una excepción con 4xx/5xx
# Parseo de la respuesta JSON a un diccionario
user = response.json()
print(user["name"])Ejemplo de recogida de todas las páginas (offset/limit):
def fetch_all_users():
users, page = [], 1
while True:
resp = requests.get(
"https://api.example.com/users",
params={"page": page, "limit": 50},
timeout=10,
)
resp.raise_for_status()
batch = resp.json()["data"]
if not batch:
break
users.extend(batch)
page += 1
return usersJavaScript (Node.js / navegador)
El fetch integrado devuelve una promesa; el JSON se parsea con el método .json().
const url = "https://api.example.com/users/42";
const response = await fetch(url, {
headers: { Authorization: "Bearer YOUR_TOKEN" },
});
// Comprobación del estado
if (!response.ok) {
throw new Error(`Error de API: ${response.status}`);
}
// Parseo del JSON
const user = await response.json();
console.log(user.name);Ejemplo de envío de datos (POST):
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_TOKEN",
},
body: JSON.stringify({ name: "Ana", role: "admin" }), // serialización
});
const created = await response.json();Java
El Java moderno incluye un HttpClient integrado; para parsear el JSON se usa una biblioteca (aquí, Jackson).
import java.net.URI;
import java.net.http.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
public class ApiExample {
public static void main(String[] args) throws Exception {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users/42"))
.header("Authorization", "Bearer YOUR_TOKEN")
.GET()
.build();
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Error de API: " + response.statusCode());
}
ObjectMapper mapper = new ObjectMapper();
JsonNode user = mapper.readTree(response.body());
System.out.println(user.get("name").asText());
}
}Go
La biblioteca estándar ofrece tanto el cliente HTTP (net/http) como el parser (encoding/json).
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type User struct {
Name string `json:"name"`
}
func main() {
req, _ := http.NewRequest("GET", "https://api.example.com/users/42", nil)
req.Header.Set("Authorization", "Bearer YOUR_TOKEN")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
panic(fmt.Sprintf("Error de API: %d", resp.StatusCode))
}
var user User
json.NewDecoder(resp.Body).Decode(&user) // parseo del cuerpo en flujo
fmt.Println(user.Name)
}C
En .NET se usan HttpClient y el System.Text.Json integrado.
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
record User(string Name);
class Program
{
static async Task Main()
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_TOKEN");
var response = await client.GetAsync("https://api.example.com/users/42");
response.EnsureSuccessStatusCode();
// Parseo del JSON directamente a un objeto tipado
var user = await response.Content.ReadFromJsonAsync<User>();
Console.WriteLine(user?.Name);
}
}PHP
Con cURL se realiza la petición y json_decode parsea la respuesta.
<?php
$ch = curl_init("https://api.example.com/users/42");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer YOUR_TOKEN"]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status !== 200) {
throw new Exception("Error de API: $status");
}
// Parseo del JSON a un array asociativo
$user = json_decode($body, true);
echo $user["name"];Rust
La combinación habitual: el cliente asíncrono reqwest y serde para el parseo.
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::Client::new();
let response = client
.get("https://api.example.com/users/42")
.header("Authorization", "Bearer YOUR_TOKEN")
.send()
.await?;
if !response.status().is_success() {
return Err(format!("Error de API: {}", response.status()).into());
}
// Parseo del JSON a una estructura
let user: User = response.json().await?;
println!("{}", user.name);
Ok(())
}Comparativa de herramientas
| Lenguaje | Cliente HTTP | Parseo de JSON |
|---|---|---|
| Python | requests / httpx |
.json() (json) |
| JavaScript | fetch / axios |
.json() (JSON) |
| Java | HttpClient |
Jackson / Gson |
| Go | net/http |
encoding/json |
| C# | HttpClient |
System.Text.Json |
| PHP | cURL / Guzzle | json_decode |
| Rust | reqwest |
serde / serde_json |
Buenas prácticas
Para construir una integración fiable con una API conviene seguir unos cuantos principios:
- Compruebe siempre el código de estado antes de parsear el cuerpo de la respuesta.
- Envuelva el parseo en un manejo de errores — los datos externos no son de fiar.
- No guarde secretos en el código — use variables de entorno.
- Respete los límites de peticiones — aplique esperas y backoff ante un 429.
- Defina timeouts en cada petición para no quedarse colgado.
- Registre las peticiones y los errores — simplifica la depuración de las integraciones.
- Cachee los datos que cambian poco para reducir la carga y no agotar los límites.
- Fije la versión de la API y siga los avisos de obsolescencia.
- Valide la estructura de la respuesta antes de usar sus campos.
Conclusión
La extracción de datos vía API es el ciclo completo de interacción con un servicio externo: construcción de la petición, autenticación, comprobación del estado y de las cabeceras, parseo del cuerpo de la respuesta y gestión de los casos límite — la paginación, los límites y los fallos de red. Técnicamente, el paso de parseo casi siempre se reduce a procesar JSON, pero una integración robusta exige tener en cuenta todo lo que lo rodea.
Hay herramientas en todos los lenguajes extendidos: en unos, el cliente HTTP y el parser vienen integrados; en otros se recurre a bibliotecas populares. El principio es el mismo en todas partes — convertir la respuesta de un servicio remoto en datos fiables con los que se pueda trabajar sin sorpresas en el código.
Para profundizar en el propio paso de parseo de los datos, consulte el artículo «Parseo de JSON»; sobre el parseo de otros formatos de respuesta, los artículos «Parseo de XML» y «Parseo de CSV».