Los datos están en su máximo esplendor en estos últimos años y algunas empresas han liberado sus datos usando su propia API REST y, de vez en cuando, queremos mostrar esos datos en nuestro WordPress.
Al hablar de datos, se nos viene a la mente infinidad de cosas, por ejemplo, datos de:
- Libros.
- Redes sociales.
- Casas y/o terrenos.
- Productos e-commerce.
- Pagos por Internet.
- Dinero y/o criptomonedas.
Los ejemplos anteriores son unos cuántos de la infinidad de datos que existen en el Internet. Pero, ¿cómo obtenemos esos datos y los mostramos en nuestro WordPress?
La solución es: API REST externas.
¿Qué es una API REST?
Una API REST es una interfaz entre sistemas que utilizan peticiones HTTP para obtener y/o modificar datos, y hasta ejecutar funcionalidades específicas de la API REST.
Las respuestas de estas peticiones HTTP serán en formato JSON o XML, y podrás hacer lo que quieras con ellas con tu lenguaje de programación favorito.
Si no sabes qué son las peticiones HTTP, sigue éste enlace para saber más al respecto (las peticiones más comunes son: GET
y POST
).
Gráficamente, así es como funciona una petición a una API REST:
La lógica de la imagen anterior se explica de la siguiente manera:
- El cliente quiere conocer los estados del país México.
- Hay que hacer una petición a la API REST de
/servicios/estados/
. - A la petición hay que adjuntarle un parámetro
{ "pais": "México" }
. - El parámetro funciona como filtro para obtener los estados de nuestro país.
- Al final, nosotros decidiremos qué hacer con los resultados de la petición.
La API REST de CoinMarketCap
Vamos a desarrollar un pequeño plugin que se conecte a la API de CoinMarketCap; es una web que te muestra los precios de todas las criptomonedas que hay en el mercado.
Lo que queremos hacer es obtener las últimas 5 criptomonedas más populares del mercado y mostrarlas en nuestra barra de administración de WordPress, justo así:
Deberás crear una cuenta en CointMarketCap siguiendo los pasos en su guía. Lo importante que necesitaremos será la API Key.
¿Qué límites tiene la API REST de CoinMarketCap?
Ten en cuenta que la cuenta básica de la API de CoinMarketCap tiene un límite de 333 créditos por día y hasta 10,000 llamadas al mes, cada crédito equivale a un request a la API.
La mayoría de APIs siguen este mismo método para evitar el abuso de peticiones por parte de bots automatizados.
Así que debes tener en cuenta cómo administras tus llamadas a la API para poder ahorrar costos a mediano y largo plazo. En este post te explico algunas buenas prácticas a seguir después de implementar una API REST externa en WordPress.
¿Qué es la HTTP API de WordPress?
WordPress contiene un conjunto de funciones que pertenecen a la HTTP API, y sirven para hacer peticiones HTTP a API REST ó cualquier otro servidor que retorne alguna respuesta. Así mismo, también contiene funciones para leer dichas respuestas.
Lo que aprendas a continuación, te servirá para tus plugins y temas WordPress que desarrolles en el futuro.
¿Cómo usar la HTTP API de WordPress?
¿No sabes cómo hacer un plugin WordPress? Lee mi post donde te explico lo que necesitas para poder desarrollarlos.
Entonces, te comentaba sobre unas funciones de WordPress para hacer peticiones a una API REST, una de ellas es wp_remote_request():
wp_remote_request( string $url, array $args );
Ésta acepta dos parámetros:
$url
(string) – La URL donde haremos nuestra petición.$args
(array) – Los argumentos de nuestra petición.
Endpoint y argumentos de la API REST
En nuestro caso, la URL de nuestra petición sería la siguiente:
https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest
Y también debemos especificar la API KEY generada por CoinMarketCap dentro de un header llamado X-CMC_PRO_API_KEY
. Todos los headers deben de estar dentro de un arreglo con índice headers
(al mismo tiempo headers
es un arreglo) así como se ve en el siguiente código:
$api_endpoint = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest';
$api_args = array( 'headers' => array( 'X-CMC_PRO_API_KEY' => 'TU API DE COINMARKETCAP' ) );
$queries = array(
'start' => 1,
'limit' => 5,
'convert' => 'MXN',
);
Usaremos las tres variables anteriores para construir y hacer la llamada a la API:
$api_endpoint
– Este es en endpoint donde se hará la petición.$api_args
– Un arreglo que contiene la API KEY dentro de las cabeceras (headers). Si no especificas este valor, la API retornará un error.$queries
– Son los query strings que serán usados en el endpoint para modificar la respuesta de la API.
Puedes cambiar los valores de la variable $queries
, por ejemplo, si quieres convertir a EUR
en vez de MXN
, simplemente especificas EUR
en el índice convert
del arreglo.
Si quieres obtener 10 o más criptomonedas en vez de 5, solo cambia el valor del índice limit
del arreglo.
Visita la documentación de la API de CoinMarketCap para más información de los parámetros que aceptan sus URLs.
Adjunta los argumentos a la petición
También dijimos que acepta un segundo parámetro, los argumentos:
$args = array(
'method' => 'GET',
);
¡Sorpresa! Tenemos que especificarle qué tipo de método HTTP usará nuestra petición, en este caso la documentación de la API nos dice que usemos GET
para la petición.
Con los códigos anteriores, tenemos este código:
$api_endpoint = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest';
$api_args = array(
'method' => 'GET',
'headers' => array( 'X-CMC_PRO_API_KEY' => 'TU API DE COINMARKETCAP' )
);
$queries = array(
'start' => 1,
'limit' => 5,
'convert' => 'MXN',
);
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_request( $api_endpoint, $api_args );
Nota la función add_query_arg()
, esta se dedica a adjuntar todos los valores existentes de la variable $queries
como query strings al endpoint que nosotros especifiquemos. El resultado de esa función será:
https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?start=1&limit=5&convert=MXN
Y listo, ya estamos haciendo una petición a la API REST de CoinMarketCap.
¿Cómo obtener el resultado de la petición API REST?
Podemos asignar el resultado de la petición a una variable, en este caso, se la asignamos a la variable $response;
y aquí viene otra de las funciones de la HTTP API de WordPress, wp_remote_retrieve_body()
:
wp_remote_retrieve_body( array $response );
Y como ven, acepta un parámetro de tipo array, y ahí es justo donde vamos a poner nuestra variable $response
, la cual contiene la respuesta de nuestra petición.
Entonces, nuestro código sería:
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_request( $api_endpoint, $api_args );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
¿En verdad funciona? Momento de probar
¡Sí funciona! Si mandamos a imprimir la variable $cryptos
con la función var_dump()
, veríamos lo siguiente:
Convierte el resultado JSON a un arreglo (array)
Hasta aquí todo bien, pero ahora tenemos un problema, el resultado en sí está en formato JSON, y tenemos que convertirlo a un array para que PHP lo pueda leer correctamente; esto lo hacemos con la función json_decode()
:
json_decode( string $string, bool $assoc_array );
La cual acepta dos parámetros:
$string
(string) – El JSON string a decodificar.$assoc_array
(bool) – Si queremos que la decodificación sea un array o no.
Y lo implementamos en nuestro código; nota que el segundo parámetro de la función json_decode()
es true
:
$response = wp_remote_request( $api_endpoint, $api_args );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
¡Bien! Nuestra variable $cryptos
ya es un array
.
Prepara tu barra de administración
Pero si recuerdan, les dije que debíamos agregar las criptomonedas en nuestra barra de administración de WordPress. ¡No temas! Es totalmente sencillo.
Tenemos que usar el hook llamado admin_bar_menu
, el cual nos permite agregar un nuevo menú en la barra de administración:
add_action( 'admin_bar_menu', 'wp_cmkcap_add_admin_bar_menu', 999 );
El código anterior nos indica que ejecutará la función wp_cmkcap_add_admin_bar_menu()
en el momento que el hook admin_bar_menu
sea ejecutado.
Crea el menú principal
Ten mucho en cuenta que la función acepta un parámetro ($wp_admin_bar
) de tipo WP_Admin_Bar
, éste será muy importante, porque nos permitirá agregar nuestro menú:
function wp_cmkcap_add_admin_bar_menu( $wp_admin_bar ) {
//
}
A continuación, agregamos nuestro título principal del menú:
$parent_node = array(
'id' => 'wp_cmkcap_admin_bar',
'title' => 'Cryptocurrencies',
);
$wp_admin_bar->add_node( $parent_node );
Ten en cuenta el método add_node()
, éste será el encargado de agregar nuestro menú a la barra de administración de WordPress. Y recuerda muy bien qué valor le estás poniendo al índice id
de la variable $parent_node
.
Agrega los títulos dentro del menú
¿Recuerdan que convertimos nuestra respuesta JSON a un array? Bien, pues ahora lo leemos con la función foreach
de PHP:
foreach ( $cryptos['data'] as $crypto_data ) {
$price = number_format( $crypto_data['quote'][ $queries['convert'] ]['price'] );
$child_node = array(
'id' => 'cryptocurrency-' . $crypto_data['id'],
'title' => $crypto_data['name'] . ' / $' . $price . ' ' . $queries['convert'],
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
}
La variable $cryptos
con índice data
contendrá toda la información de la criptomoneda, entonces si queremos solo el nombre de la criptomoneda, tendríamos que llamar a la variable de la siguiente forma:
$crypto_data['name'];
Puedes revisar qué información contiene $crypto_data
en la imagen cuando hicimos el var_dump()
.
Y ahora, quiero que pongas atención en el valor del índice title
dentro de la variable $child_node
:
$child_node = array(
'id' => 'cryptocurrency-' . $crypto_data['id'],
'title' => $crypto_data['name'] . ' / $' . $price . ' ' . $queries['convert'],
'parent' => 'wp_cmkcap_admin_bar',
);
En el índice title
es donde pondremos el nombre de la criptomoneda concatenado con su precio en pesos mexicanos, para este ejemplo.
Y el valor del índice parent
tendrá que ser igual al valor del índice id
que le pusiste en tu variable $parent_node
. Esto para que cada título de la criptomoneda se vaya agregando abajo del menú Cryptocurrencies.
Con el código anterior unido, la función wp_cmkcap_add_admin_bar_menu()
se vería de esta manera:
function wp_cmkcap_add_admin_bar_menu( $wp_admin_bar ) {
$parent_node = array(
'id' => 'wp_cmkcap_admin_bar',
'title' => 'Cryptocurrencies',
);
$wp_admin_bar->add_node( $parent_node );
$api_endpoint = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest';
$api_args = array(
'method' => 'GET',
'headers' => array( 'X-CMC_PRO_API_KEY' => 'TU API DE COINMARKETCAP' )
);
$queries = array(
'start' => 1,
'limit' => 5,
'convert' => 'MXN',
);
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_request( $api_endpoint, $api_args );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
foreach ( $cryptos['data'] as $crypto_data ) {
$price = number_format( $crypto_data['quote'][ $queries['convert'] ]['price'] );
$child_node = array(
'id' => 'cryptocurrency-' . $crypto_data['id'],
'title' => $crypto_data['name'] . ' / $' . $price . ' ' . $queries['convert'],
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
}
}
Posibles errores de la petición API REST
Es muy común que las API REST que estemos utilizando devuelvan varios tipos de errores. Un error tal vez ocurra porque:
- Te faltó especificar la API KEY para autenticar tu sesión.
- Un parámetro que mandaste a la API está mal escrito y no existe.
- El endpoint no existe.
- El servicio de la API REST está fuera de servicio (timeout).
Si uno de los errores anteriores u otros sucede, en este momento en que el código no tiene validaciones contra errores, te devolvería un error PHP. Y no queremos eso.
Validación del timeout
En el caso de un timeout por parte de la API REST, la función wp_remote_request()
retornará una instancia de tipo WP_Error
como respuesta y la validamos con la función is_wp_error()
:
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_get( $api_endpoint, $api_args );
if ( is_wp_error( $response ) ) {
$child_node = array(
'id' => 'internal-error',
'title' => 'Internal Error - Notify the administrator.',
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
return;
}
El código anterior menciona que si la variable $response
es una instancia de WP_Error
entonces agrega un mensaje de error adentro de nuestro menú:
Validaciones al código HTTP de la petición API REST
Ahora podemos agregar las validaciones a otros tipos de errores. Por ejemplo, si hubiésemos especificado el endpoint a una ruta que no existe, la API devolverá el siguiente resultado:
{
"statusCode": 404,
"error": "Not Found",
"message": "Not Found"
}
Y este error cuando no especificamos la API KEY en la petición:
{
"status": {
"timestamp": "2021-04-18T18:41:41.318Z",
"error_code": 1002,
"error_message": "API key missing.",
"elapsed": 0,
"credit_count": 0
}
}
Aquí tenemos respuestas diferentes en ambos casos, el primer resultado es un código HTTP 404 y el segundo es un 401. Significa que tenemos que agregar validaciones de acuerdo al código HTTP devuelto.
Para obtener el código HTTP actual de la petición tenemos que usar la función wp_remote_retrieve_response_code( $response )
para después usar la respuesta de esa función dentro de una condición:
$http_code = wp_remote_retrieve_response_code( $response );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
if ( 200 !== $http_code ) {
$message = 404 === $http_code ? $cryptos['message'] : $cryptos['status']['error_message'];
$child_node = array(
'id' => 'api-error',
'title' => 'API Error: ' . $message,
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
return;
}
El código anterior menciona que si el código HTTP es diferente al número 200 (equivalente a un resultado exitoso) entonces obtendrá los mensajes de error y los insertará dentro de nuestro menú.
¡Ojo! Aquí tenemos que agregar una validación ternaria (variable $message
) para obtener el mensaje de error ya que el resultado del error 404 es muy diferente al del error 401. Ten en cuenta este tipo de situaciones para evitar futuros errores.
Con las validaciones integradas, el menú se verá así cuando algún error suceda:
Resultado final
¡Listo! Hemos terminado, descarga el código completo y ejecútalo en tu WordPress y verás cómo funciona a la perfección, así es como se debería ver el código:
/*
Plugin Name: WP CoinMarketCap
Plugin URI: https://roelmagdaleno.com/
Description: Get the latest cryptocurrency data.
Version: 2.0
Author: Roel Magdaleno
Author URI: https://roelmagdaleno.com/
License: GPL2
License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
function wp_cmkcap_add_admin_bar_menu( $wp_admin_bar ) {
$parent_node = array(
'id' => 'wp_cmkcap_admin_bar',
'title' => 'Cryptocurrencies',
);
$wp_admin_bar->add_node( $parent_node );
$api_endpoint = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest';
$api_args = array( 'headers' => array( 'X-CMC_PRO_API_KEY' => 'TU API DE COINMARKETCAP' ) );
$queries = array(
'start' => 1,
'limit' => 5,
'convert' => 'MXN',
);
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_get( $api_endpoint, $api_args );
if ( is_wp_error( $response ) ) {
$child_node = array(
'id' => 'internal-error',
'title' => 'Internal Error - Notify the administrator.',
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
return;
}
$http_code = wp_remote_retrieve_response_code( $response );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
if ( 200 !== $http_code ) {
$message = 404 === $http_code ? $cryptos['message'] : $cryptos['status']['error_message'];
$child_node = array(
'id' => 'api-error',
'title' => 'API Error: ' . $message,
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
return;
}
foreach ( $cryptos['data'] as $crypto_data ) {
$price = number_format( $crypto_data['quote'][ $queries['convert'] ]['price'] );
$child_node = array(
'id' => 'cryptocurrency-' . $crypto_data['id'],
'title' => $crypto_data['name'] . ' / $' . $price . ' ' . $queries['convert'],
'parent' => 'wp_cmkcap_admin_bar',
);
$wp_admin_bar->add_node( $child_node );
}
}
add_action( 'admin_bar_menu', 'wp_cmkcap_add_admin_bar_menu', 999 );
Funciones de ayuda
Pero podríamos usar otra función para hacer nuestras peticiones en vez de wp_remote_request()
, y sería la función wp_remote_get(), la cual acepta los mismos parámetros que la función que hemos usado anteriormente.
Solo que le pasamos únicamente el primer parámetro, que es la URL de la API REST; el código quedaría de ésta forma:
$api_endpoint = 'https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest';
$api_args = array( 'headers' => array( 'X-CMC_PRO_API_KEY' => 'TU API DE COINMARKETCAP' ) );
$queries = array(
'start' => 1,
'limit' => 5,
'convert' => 'MXN',
);
$api_endpoint = add_query_arg( $queries, $api_endpoint );
$response = wp_remote_get( $api_endpoint, $api_args );
$cryptos = json_decode( wp_remote_retrieve_body( $response ), true );
Nótese que hemos eliminado la variable $args
, (donde le decíamos que íbamos a hacer una petición GET
) ya que ésta función es solamente para hacer peticiones HTTP GET
.
Si tu API te pide una petición HTTP POST
, entonces usarías la función wp_remote_post().
Puntos a tomar en cuenta
Cada API REST es diferente, nos piden distintos parámetros y alguno de ellos nos podría pedir ciertos argumentos, como cabeceras HTTP, el tiempo de espera del servidor, si desea verificar el SSL, entre otros. Si llegases a usar un argumento, lo tendrías que especificar dentro de la variable $args
, por ejemplo:
$args = array(
'timeout' => 30,
'httpversion' => '1.1',
'sslverify' => false,
'body' => array(
'username' => 'avengers',
'password' => 'infinitywars',
),
);
wp_remote_post( $api_url, $args );
Otro punto a tomar en cuenta es que algunas API REST necesitarán una API KEY para poder realizar nuestras peticiones exitosamente; tienes que revisar en la documentación de la API REST que estés usando, si necesitas una API KEY para empezar a utilizar su recurso.
De vez en cuando, las API REST podrían alentar un poco tu sitio, todo depende de qué tan rápida sea la respuesta de la API REST que estés utilizando. La solución a esto es que sólo hagas una única petición al momento de activar tu plugin y guardes el resultado de la petición en un valor en tu base de datos, y de ahi vas leyendo su valor, así te ahorras las llamadas que podrían arruinar tu sitio.
Recursos para API REST y WordPress
¿Te interesa seguir trabajando con API REST y WordPress? Aquí te dejo algunos recursos:
- Lista de APIs públicas.
- La HTTP API de WordPress.
- Insomnia. Un programa para hacer peticiones HTTP a API REST.
Si has llegado hasta aquí, ¡te felicito!
Ahora, te invito a que en los comentarios me expongas tus dudas que surgieron a lo largo del post ó las ideas que tienes sobre cómo implementar esto en algún plugin.
Si con éste tutorial has hecho un plugin parecido al que acabamos de desarrollar, comenta con un screenshot los resultados y explícanos de que se trata. 🙂
Changelog
18/04/2021
- El endpoint, de CoinMarketCap, de ejemplo inicial se cambió porque dejó de existir. Ahora se usa un nuevo endpoint que requiere API KEY. El lector debe registrarse y obtener una API KEY para continuar con la guía.
- Ahora se usa la función
add_query_arg()
para adjuntar los query strings al endpoint final. - Se agregó la sección de manejo de errores donde se valida ciertos errores de la API.
- El código final se almacena en Gist en vez de descargarlo en formato ZIP.
Deja un comentario