Cotizaciones, clima, pagos, envíos, inteligencia artificial: buena parte del valor de una aplicación moderna viene de conectarse con servicios externos a través de sus APIs. Desde PHP es sencillo, pero hay detalles (timeouts, códigos de error, credenciales) que separan un script que funciona en tu máquina de uno que aguanta en producción. En el libro PHP desde cero hasta experto aprendes a consumir APIs externas y a crear las tuyas; aquí nos centramos en consumirlas bien.
file_get_contents o cURL
| file_get_contents | cURL | |
|---|---|---|
| Simplicidad | Una línea para un GET | Algo más de código |
| Métodos, cabeceras, cuerpo | Posible con un “stream context”, incómodo | Control total |
| Timeouts y errores detallados | Limitados | Completos |
| Úsalo para | Pruebas rápidas | Cualquier integración real |
Si tu proyecto usa Composer, la librería Guzzle ofrece una interfaz más cómoda sobre lo mismo. Entender cURL primero te ayudará a usar cualquier cliente HTTP.
Petición GET y lectura de JSON
Este ejemplo consulta la API pública de GitHub para obtener datos del repositorio de PHP:
<?php
$ch = curl_init('https://api.github.com/repos/php/php-src');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, // devolver la respuesta en vez de imprimirla
CURLOPT_TIMEOUT => 10, // segundos máximos de espera
CURLOPT_HTTPHEADER => [
'Accept: application/vnd.github+json',
'User-Agent: mi-app-php', // GitHub exige un User-Agent
],
]);
$respuesta = curl_exec($ch);
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($respuesta === false || $codigo !== 200) {
exit('No se pudo consultar la API.');
}
$repo = json_decode($respuesta, true); // true = arrays asociativos
echo "{$repo['full_name']} tiene {$repo['stargazers_count']} estrellas.";
Una función reutilizable para cualquier API
Repetir esas líneas en cada llamada es una invitación a olvidarse del timeout o de comprobar el código de respuesta. Mejor encapsularlo una vez:
<?php
declare(strict_types=1);
function apiRequest(string $metodo, string $url, ?array $datos = null, array $cabeceras = []): ?array
{
$cabeceras[] = 'Accept: application/json';
$opciones = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $metodo,
CURLOPT_CONNECTTIMEOUT => 5, // tiempo para conectar
CURLOPT_TIMEOUT => 15, // tiempo total
];
if ($datos !== null) {
$opciones[CURLOPT_POSTFIELDS] = json_encode($datos, JSON_THROW_ON_ERROR);
$cabeceras[] = 'Content-Type: application/json';
}
$opciones[CURLOPT_HTTPHEADER] = $cabeceras;
$ch = curl_init($url);
curl_setopt_array($ch, $opciones);
$cuerpo = curl_exec($ch);
if ($cuerpo === false) {
throw new RuntimeException('Error de red: ' . curl_error($ch));
}
$codigo = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($codigo >= 400) {
throw new RuntimeException("La API respondió con el código $codigo", $codigo);
}
return $cuerpo === '' ? null : json_decode($cuerpo, true, flags: JSON_THROW_ON_ERROR);
}
La función lanza una excepción ante cualquier problema, así que quien la usa decide qué hacer: reintentar, mostrar un mensaje o registrar el error. Lo vemos a fondo en manejo de errores y excepciones.
POST con JSON y autenticación
<?php
declare(strict_types=1);
require_once __DIR__ . '/lib/http.php';
// La clave de la API, desde una variable de entorno: nunca escrita en el código
$token = getenv('API_ENVIOS_TOKEN');
try {
$envio = apiRequest('POST', 'https://api.ejemplo.com/v1/envios', [
'destinatario' => 'Ana Pérez',
'direccion' => 'Av. Siempre Viva 742',
'peso_kg' => 1.2,
], ["Authorization: Bearer $token"]);
echo 'Envío creado con número de seguimiento ' . htmlspecialchars($envio['tracking']);
} catch (RuntimeException $e) {
error_log($e->getMessage());
echo 'No pudimos crear el envío. Intenta de nuevo en unos minutos.';
}
htmlspecialchars() antes de mostrarla.
Caché para no saturar la API
Muchas APIs limitan el número de peticiones por minuto, y además cada llamada añade espera a tu página. Si el dato no cambia a cada segundo (una cotización, el clima), guárdalo un rato:
<?php
declare(strict_types=1);
function conCache(string $clave, int $segundos, callable $obtener): mixed
{
$archivo = sys_get_temp_dir() . '/cache_' . md5($clave) . '.json';
if (is_file($archivo) && time() - filemtime($archivo) < $segundos) {
return json_decode(file_get_contents($archivo), true);
}
$datos = $obtener();
file_put_contents($archivo, json_encode($datos), LOCK_EX);
return $datos;
}
// La API solo se consulta, como mucho, una vez cada 10 minutos
$repo = conCache('github-php-src', 600, fn() => apiRequest('GET', 'https://api.github.com/repos/php/php-src', null, ['User-Agent: mi-app-php']));
Errores comunes
- No poner timeout: si la API se cuelga, tu página también, y cada visitante ocupa un proceso del servidor esperando.
- Desactivar la verificación SSL (
CURLOPT_SSL_VERIFYPEER => false) para “arreglar” un error de certificado: abre la puerta a ataques de intermediario. Arregla el certificado o el paquete de CA del servidor. - Dar por hecho que la respuesta es JSON válido: una página de error HTML hará que
json_decodedevuelvanull. - Subir claves de API a GitHub: usa variables de entorno o un archivo de configuración excluido del repositorio.
Consume y crea tus propias APIs
El libro PHP desde cero hasta experto enseña a consumir APIs externas y a crear tus propias APIs RESTful con PHP y MySQL.
Comprar en Amazon