> Manuales > Manual de Ajax práctico

Qué es JSONP y por qué se utiliza en el desarrollo de sitios web. Ejemplos JSONP en la librería Javascript jQuery.

JSONP

El uso de APIs en el mundo del desarrollo web está cada vez más extendido y JSON se ha popularizado como el formato de intercambio de información más utilizado. Es ligero y compatible con la mayoría de los sistemas donde lo puedas llegar a consumir.

En el mundo de la web y con respecto a la programación del lado del cliente, es habitual que queramos consultar datos que vienen de APIs REST para realizar aplicaciones enriquecidas. Esos datos pueden estar alojados en nuestro servidor o en servidores remotos, en cuyo caso podría haber algunas restricciones de seguridad. Para evitar estas restricciones puede que hayas oído hablar en alguna ocasión de JSONP.

En este artículo queremos profundizar en la materia y contarte algunas diferencias entre JSON y JSONP, así como los motivos y modos de uso de JSONP.

Problemática de seguridad con JSON

Quizás alguna vez has advertido que, en ciertas ocasiones, no es posible hacer una llamada a Ajax a través de dominios distintos para traernos algún dato. Esto es una limitación en la programación web del lado del cliente y es debido a una restricción de seguridad de los navegadores.

La causante de ese problema es una política llamada "Same-origin policy", que está pensada para evitar que se carguen mediante Javascript datos potencialmente inseguros, por estar en otros servidores. Es decir, los datos que nos traemos mediante Ajax conectando con nuestro propio dominio son considerados seguros, pero en el caso que estén en otros dominios de Internet son afectados por la política de origen cruzado (CORS), por lo que tienen existen una serie de medidas extra que se deben implementar en los servidores de consulta, encaminadas a garantizar la seguridad.

Esta restricción se puede evitar si el dominio con el que te conectas está configurado para aceptar conexiones desde otros dominios. Esto se consigue activando la configuración "Cross-origin resource sharing" (CORS), pero también puede solucionarse, independientemente de la configuración del servidor, a través del uso de JSONP.

Qué es JSONP

JSON y JSONP son básicamente lo mismo, un formato ligero para intercambiar datos con notación de objeto Javascript. La notación no difiere en absoluto entre JSON y JSONP, pero sí la "envoltura". En JSONP en lugar de viajar el dato a secas como en JSON, lo que viaja es una función generalmente llamada "callback". Esa función es como un Javascript, que engloba el dato que hemos solicitado. De ahí que a veces se conozca a JSONP como JSON con padding.

Nota: No comentamos mucho acerca de JSON porque ha sido motivo de diversos artículos. Para referencia puedes consultar el Videoturorial de JSON.

Cómo evitar las restricciones de la política del mismo origen

Quizás te preguntes: Si hemos dicho que debido a la restricción de los navegadores "Same-origin policy" no se puede acceder a datos que residen en servidores externos. ¿Por qué puedo acceder a los datos JSONP y no a los JSON normales?

Realmente son lo mismo, solo cambia un poco de esa envoltura de la función en JSONP. ¿Cuál es la magia?

Como hemos dicho, la manera general de saltarse las restricciones de Same-origin policy es implementar CORS en el servidor que se consulta. Esto consiste en colocarle unas cabeceras a las respuestas que habilitan a los clientes realizar las consultas.

Sin embargo, no siempre es posible en el servidor configurar esas cabeceras de respuesta, por el motivo que sea. Entonces existe una manera de trabajar alternativa.

Una respuesta JSON tiene una forma como esta:

{
  "nombre": "Manuel",
  "edad": 35
}

El dato se obtiene mediante Ajax, usando las funciones XMLHttpRequest o cualquier otra interfaz de comunicaciones asíncronas. JSON te lo entrega en "crudo" (el dato y nada más).

Por su parte, JSONP lo que te entrega es una invocación a una función Javascript, en la que se envía por parámetro el dato que se desea devolver.

miFuncion({"nombre":"Manuel", "edad":35});

Esto es código Javascript normal, generado por el servidor que estamos consultando. Por supuesto el servidor consultado lo puede haber generado a partir de una base de datos o cualquier otro recurso.

La otra diferencia fundamental de JSONP es el modo de consumir ese dato en el cliente. Si al dato JSON accedemos mediante Ajax, al dato JSONP se accede mediante una etiqueta <script>. Ésta es la principal diferencia, pues el consumo de un código Javascript cargado mediante la etiqueta <script> no tiene esas restricciones de política del mismo origen.

Así pues, lo que tendríamos que hacer para acceder a un dato JSONP es utilizar un script con su atributo src.

<script src="http://example.com/dato_que_viene_con_JSONP.php"></script>

Para hacer posible el JSONP en situaciones cross-domain se usa una alternativa permitida de carga de scripts en una página. Como sabes, el navegador sí que acepta la carga de código Javascript que traigas con la etiqueta SCRIPT y el atributo src de otro dominio. Es la base de los servicios CDN.

<script src="http://example.com/cdn/libreria-js/que-traigo-por-cdn"></script>

Debido a que eso no provoca ningún problema de seguridad, JSONP se aprovecha de ello para acceder de ese modo al recurso solicitado, inyectando ese script en la página y ejecutando su código para extraer el dato.

Fíjate que si te llegase un JSON normal no podrías ejecutarlo tal cual. El JSON es un literal de objeto y no una sentencia Javascript que sea capaz de ejecutar el navegador, por ello no podrías meterlo tal cual en una etiqueta SCRIPT de la página.

Ejemplo de consumo de un JSONP

Ahora nos vamos a centrar en cómo consumir un dato que nos viene de JSONP. Primero vamos a poner un ejemplo de URL típica que podríamos usar para acceder a un dato JSONP:

http://example.com/usuarios.json?callback=micallback

La clave en esta URL consiste en que, al llamar al servicio web se indica una función callbak llamada en este ejemplo "micallback".

En un ejemplo como este que funciona con JSONP lo que recibes es algo como esto:

micallback({
	"datos": "del",
	"json": "con JSONP"
})

Como puedes comprobar, el servidor te ha generado una envoltra al JSON con la invocación a la función que le has pasado por parámetro en la URL (micallback).

Ya que JSONP es una llamada a una función callback, para que se pueda utilizar el dato debemos tener esa función callback como código Javascript del lado del cliente.

function micallback(dato) {
    console.log(dato);
}

Existiendo esa función en Javascript, cuando se trae el JSONP y se procese (por haber sido injectado en una etiqueta Javascript), se invocará enviando como parámetro el dato.

Esa función micallback(), o como quiera que se llame, será encargada de hacer lo que sea necesario con el dato enviado. Por supuesto, mostrar en consola el dato no es algo típico que querrás hacer, sino más bien manipular algún elemento de la página para mostrar la información.

function micallback(dato) {
    document.getElementById('elementoNombre').innerText = dato.nombre;
    document.getElementById('elementoEdad').innerText = dato.edad;
}

Generación automática de la etiqueta script

Otro detalle interesante sobre cómo se consume un JSONP lo tenemos en la llamada al servidor de consulta para recuperar el dato. Lo normal es que en la página no exista la etiqueta <script> que se debe utilizar para traerse el dato por JSONP, en su lugar tendremos una función que se encarga de generar el script al vuelo.

function obtenerJSONP(url_consulta) {
  let scriptObject = document.createElement("script");
  scriptObject.src = url_consulta;
  document.body.appendChild(scriptObject);
}

Cuando se necesite traer un dato por JSONP, en vez de hacer la llamada a Ajax, se invocará a una función como la anterior obtenerJSONP() que recibe la URL del recurso que se desea obtener. Esta función genera la etiqueta script al vuelo con Javascript, le coloca el src adecuado y luego añade esa etiqueta generada en el cuerpo de la página.

Cómo procesar un JSONP para extraer el dato con jQuery

Afortunadamente nuestra librería Javascript preferida debe ser capaz de extraer ese dato por nosotros, de una manera semi-transparente. Generalmente solo tendremos que advertir que vas a recibir el dato en JSONP en lugar de JSON tradicional.

Lógicamente la forma que haremos esto depende de la construcción de tu librería. Veamos ahora algunos ejemplos de código. Verás que es bastante sencillo.

Para indicar a jQuery que el dato de respuesta llega en JSONP utilizamos la variable de configuración "dataType", asignando el valor "jsonp".

Este código no te requerirá muchas explicaciones si conoces el trabajo con Ajax en jQuery. Revisa el Manual de jQuery para eventuales consultas de Ajax.

$.ajax({
url: "http://api.openbeerdatabase.com/v1/beers.json",
	data: {
		query: "beer"
	},
	type: "GET",
	dataType: "jsonp",
	success: function(respuesta){
console.log("Recibes: ", respuesta);
$("<pre>").text(JSON.stringify(respuesta)).appendTo("body");
	}
});

Lo que quiero que se vea es que en la función success() el parámetro "respuesta" tiene un objeto Javascript nativo, que es el resultado de la cadena JSONP recibida convertida en su correspondiente objeto.

Con el console.log() vuelcas ese dato en la consola de Javascript. Con la etiqueta PRE creada al vuelo y el método JSON.stringify() consigo que se convierta ese objeto a un literal de cadena, con lo que puedo volcarlo como texto en la página y verlo sin necesidad de la consola. Generalmente tú en tu programa harás con tu objeto otra cosa distinta, eso ya depende de tu aplicación y el objetivo de los datos que acabas de recibir. Lo interesante aquí es que jQuery se encarga el solito de transformarte el JSONP en un objeto manipulable por código Javascript.

De momento es todo. Espero que hayas resuelto tus dudas y no sea para ti un problema acceder a cualquier API que te devuelve datos con JSONP.

Miguel Angel Alvarez

Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...

Manual