Por lo general hay dos estrategias de paginación que suelen implementarse comúnmente. Paginación diri- gida desde el cliente y paginación “cocinada” en el servidor.
En el primer caso el cliente indica el número de elementos por página y la página que desea con- sultar y el servidor devuelve junto con la respuesta, el número de elementos existentes para que el cliente pueda preparar las siguientes llamadas. En ocasiones, el cliente no indica la página si no el elemento a partir del cual quiere recuperar y el número de elementos a recuperar. Para poder especificar esto se sue- len usar parámetros en la URL denominados page, limit, start, offset, top, etc.
En el caso de que sea el servidor quien directamente prepara la estrategia de paginado, éste sue- le montar en la respuesta los enlaces a la página anterior, siguiente, primera y última. Estos enlaces pue- den ir parametrizados de igual forma que en el caso anterior o directamente con el número de página, si el número de elementos por página ha sido negociado. Como el servidor no debe almacenar preferencias del cliente y toda la información necesaria para realizar cualquier operación, debe ir contenida en la peti- ción, lo más correcto es que el servidor defina un número de elementos por página por defecto y el clien- te lo asuma como válido en los enlaces preparados que recibe. Si el cliente quiere trabajar con un número de elementos por página diferente, siempre debería tener la posibilidad de solicitarlo ad hoc.
3.2.3.
Expansión
Cuando el servicio devuelve la representación de un recurso y éste está relacionado con otro, lo habitual suele ser presentar el enlace al recurso relacionado conforme al criterio “hypertext driven” tal y como su- cede con la entidad relacionada “Category” que se puede ver en la Ilustración 1 que se muestra a conti- nuación.
Ilustración 1 – Expansión en modo “hypertext driven”
Request: GET http://services.odata.org/V4/OData/OData.svc/Products(0) Response: { "@odata.context":"http://services.odata.org/V4/OData/OData.svc/$metadata#Products", "value":[ { "@odata.type":"#ODataDemo.Product", "@odata.id":"http://services.odata.org/V4/OData/OData.svc/Products(0)", "@odata.editLink":"Products(0)", "ID":0, "Name":"Bread",
"Description":"Whole grain bread",
"[email protected]":"#DateTimeOffset", "ReleaseDate":"1992-01-01T00:00:00Z", "DiscontinuedDate":null,
Etiquetas:API, RESTful, OData, OpenAPI Fichero: PFC_Miguel Ángel Beites García_2017.docx Departamento de Ingeniería Telemática y Electrónica.
Estado: Borrador Rev. 756 33
"Rating":4, "Price":2.5, "[email protected]":"Products(0)/Categories/$ref", "[email protected]":"Products(0)/Categories", "[email protected]":"Products(0)/Supplier/$ref", "[email protected]":"Products(0)/Supplier", "[email protected]":"Products(0)/ProductDetail/$ref", "[email protected]":"Products(0)/ProductDetail" } ] }
Si bien es cierto que esta forma de interactuar limita la cantidad de datos a transferir, elude el tiempo que se emplea en serializar los datos que de otra forma habría que enviar y simplifica la búsqueda de la información, puede que en ocasiones desencadene un comportamiento no deseable en determina- dos clientes.
Como la información se consigue de forma jerárquica, obteniendo en primer lugar el recurso de primer nivel y en base al enlace de navegación proporcionado, en segunda instancia, el recurso de segun- do nivel, esto puede provocar inconsistencias en la representación de la información en la interfaz cliente debido a la latencia de red. Supongamos que solicitamos los cien primeros recursos y por cada uno, acto seguido, las categorías a las que pertenecen. Dando por hecho que la interfaz es capaz de representar y refrescar la información según le va llegando, puede generarse cierta incoherencia en la representación de los datos, como por ejemplo si queremos mantener una agrupación por categoría. Es decir, en ocasio- nes, es preciso disponer de toda la información relacionada de forma íntegra. Es cierto que podría ser el cliente quien esperase a tener toda la información antes de lanzar su representación, pero esta lógica in- troduce cierta complejidad en el cliente probablemente innecesaria.
Para solventar esto, existe otra alternativa. La representación “inline” del recurso relacionado. Para dar soporte a este tipo de solicitud se suele emplear un parámetro en la URL que habitualmente de denomina “expand” y que recoge una lista de los recursos relacionados han de ir embebidos en la res- puesta.
Ilustración 2 – Expansión en modo “inline”
Request: GET http://services.odata.org/V4/OData/OData.svc/Products(0)?$expand=Categories Response: { "@odata.context":"http://services.odata.org/V4/OData/OData.svc/$metadata#Products", "value":[ { "@odata.type":"#ODataDemo.Product",
Departamento de Ingeniería Telemática y Electrónica.
E.T.S. de Ingeniería y Sistemas de Telecomunicación
Etiquetas:API, RESTful, OData, OpenAPI Fichero: PFC_Miguel Ángel Beites García_2017.docx
Departamento de Ingeniería Telemática y Electrónica.
34 Rev. 756 Estado: Borrador
"@odata.id":"http://services.odata.org/V4/OData/OData.svc/Products(0)", "@odata.editLink":"Products(0)",
"ID":0,
"Name":"Bread",
"Description":"Whole grain bread",
"[email protected]":"#DateTimeOffset", "ReleaseDate":"1992-01-01T00:00:00Z", "DiscontinuedDate":null, "[email protected]":"#Int16", "Rating":4, "Price":2.5, "[email protected]":"Products(0)/Categories/$ref", "[email protected]":"Products(0)/Categories", "Categories":[ { "@odata.type":"#ODataDemo.Category", "@odata.id":"http://services.odata.org/V4/OData/OData.svc/Categories(0)", "@odata.editLink":"Categories(0)", "ID":0, "Name":"Food", "[email protected]":"Categories(0)/Products/$ref", "[email protected]":"Categories(0)/Products" } ], "[email protected]":"Products(0)/Supplier/$ref", "[email protected]":"Products(0)/Supplier", "[email protected]":"Products(0)/ProductDetail/$ref", "[email protected]":"Products(0)/ProductDetail" } ] }
Como se puede ver en el ejemplo de la Ilustración 2, el servicio devuelve embebidos en la res- puesta solo aquellos recursos relacionados que fueron solicitados expresamente. El resto se conservan “hypertext driven”.
Parece por tanto una solución de compromiso en la que cliente y servidor optimizan sus recursos adecuándose a las necesidades puntuales de ambos. En una respuesta no tiene por qué ser todo “inline” o todo “hypertext driven”.
Etiquetas:API, RESTful, OData, OpenAPI Fichero: PFC_Miguel Ángel Beites García_2017.docx Departamento de Ingeniería Telemática y Electrónica.
Estado: Borrador Rev. 756 35
3.2.4.
Operaciones: funciones y acciones
Este es otro asunto un tanto controvertido puesto que incluso dando por hecho que un Servicio REST con- templa primero los DATOS y detrás el SERVICIO (y no a la inversa como ocurre en SOAP), en ocasiones existe la necesidad de dar soporte a ciertas operaciones respetando los principios de la arquitectura.
FUNCIONES como operaciones que no tienen efectos secundarios, como por ejemplo consultas con una parametrización concreta que se usan frecuentemente y que se encapsulan en una determinada fun- ción. Generalmente devolverán recursos o colecciones de recursos.
ACCIONES entendidas como operaciones que tienen efectos secundarios, como por ejemplo la modificación de datos, y que no podrían realizarse de forma segregada porque podría acarrear un com- portamiento no determinista. Éstas pueden ser el soporte necesario para las operaciones transaccionales. Por otra parte, en ocasiones puede existir la necesidad de realizar operaciones no vinculadas con un recurso concreto, escenario que parece totalmente inverso al anteriormente mencionado, posicionan- do los DATOS detrás del SERVICIO. Algunos protocolos como OData solventan esto de una forma bastante aséptica, ampliando el espectro funcional con operaciones no vinculadas a recursos, para cubrir práctica- mente cualquier necesidad sin “contaminar” los principios REST.
3.3.
Lenguajes de especificación de servicios REST y utilidades
Veremos a continuación algunos de los FORMATOS que existen para definir de la especificación de un Servi- cio o API Web REST. Cabe destacar que estos lenguajes tan solo persiguen formalizar la taxonomía de la especificación pero no especifican las pautas que deben seguir al respecto del comportamiento de las operaciones ofrecidas.
3.3.1.
OpenAPI
Open API Initiative (en adelante OAI) contempla la OpenAPI Specification (en adelante OAS) como un pro- yecto utilizado para describir y documentar las API REST. La especificación Swagger fue donada a OAI en 2015 (ver Anexo 1) y es la base de la OAS que hasta la fecha se conserva en la versión Release 2.0
La especificación Swagger es la más veterana (la versión 1.0 fue liberada en agosto de 2011) y cuenta con el respaldo de 3scale (Red Hat), Paypal (PayPal Inc.) y Apigee (Apigee Corp.) entre otros, que ha sido recientemente adquirida (el 10 noviembre de 2016, Google completó la adquisición de Apigee) por Google.
Departamento de Ingeniería Telemática y Electrónica.
E.T.S. de Ingeniería y Sistemas de Telecomunicación
Etiquetas:API, RESTful, OData, OpenAPI Fichero: PFC_Miguel Ángel Beites García_2017.docx
Departamento de Ingeniería Telemática y Electrónica.
36 Rev. 756 Estado: Borrador
OAS define un conjunto de ficheros necesarios para describir y documentar un API RESTful. SWAGGER-EDITOR permite escribir la especificación y cuenta con una vista previa simultánea y navegable que permite la interacción con el API permitiendo componer y enviar peticiones.
Estos ficheros pueden ser utilizados por el proyecto SWAGGER-UI, que permite mostrar la especifi- cación en forma de documento formal y probar el API simultáneamente, lo que facilita su comprensión.
SWAGGER-CODEGEN permite generar, a partir de los ficheros de especificación, los adaptadores clientes para multitud de lenguajes y cuenta con un completo SDK para la generación de código de servi- dor con las anotaciones Swagger para diferentes plataformas. De igual forma, existen multitud de librerías o Frameworks para diferentes lenguajes que permiten generar la especificación Swagger a partir de ano- taciones en el código fuente del servidor.
Estas utilidades pueden ser descargadas dese GitHub y pueden ser también usadas en línea des- de la web de Swager. Otras utilidades adicionales pueden usarse para explotar estos ficheros, como por ejemplo Postman [5], que resulta una herramienta tremendamente sencilla e intuitiva para la explotación y pruebas del API, que permite almacenar sets de solicitudes y orquestar flujos de pruebas.
Los archivos que describen la API REST de acuerdo con la especificación Swagger se representan como objetos JSON y se ajustan a las normas de JSON. En la versión 2.0 migraron a YAML (bastante más amigable y fácilmente interpretable por humanos) Como YAML es un superconjunto de JSON, puede ser utilizado también para representar un archivo de especificación de Swagger, conservando la compatibili- dad con JSON.
La OAS usa los términos “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALLNOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY” y “OPTIONAL”, que han de ser interpretados conforme a la RFC 2119 [6] Asi- mismo define los MIME—type soportados por los recursos conforme a la RFC 6838 [7] y los http STA- TUS—code que indican el estado de la operación ejecutada conforme a la RFC 7231 [8, p. Sec. 6] descrita en el [9]
La especificación contempla el uso de llaves ({}) en las plantillas de rutas para identificar una sec- ción de la URL, que adoptará el valor de un determinado parámetro de ruta. La especificación completa se puede ver en el Anexo 2.
OAS no tiene un soporte específico para la reutilización de código y los patrones de diseño, lo que hace que en cierto modo, mantenga siempre claramente interpretable la especificación y en contraparti- da sea susceptible de contener estructuras repetidas que compliquen el mantenimiento de la especifica- ción y comprometan su ciclo de vida.
Etiquetas:API, RESTful, OData, OpenAPI Fichero: PFC_Miguel Ángel Beites García_2017.docx Departamento de Ingeniería Telemática y Electrónica.
Estado: Borrador Rev. 756 37
OAS cuenta también con multitud de clientes que se pueden descargar, que permiten generar objetos simulados (mock object) para integrar en el código usado para las pruebas unitarias y pruebas en- tre objetos interdependientes. No es en vano que cuente con el soporte de la comunidad más amplia que posibilita el más extenso set de utilidades.
3.3.2.
RAML
RAML es la especificación más joven de las tres que veremos (RAML 0.8, fue lanzado en octubre de 2013) y está respaldada por MuleSoft y Akana (Akana, Inc.) entre otros. RAML está basado en YAML y usa JSON para especificar las estructuras de datos, denominadas esquemas. RAML fue concebido no solo para des- cribir la especificación y facilitar su documentación, sino también para modelar un API. Es por esto que se denomina lenguaje de modelado RAML. La especificación completa se puede ver en el Anexo 3.
RAMLAPIDESIGNER es una herramienta de desarrollado basada en web que permite a los provee- dores de API diseñar de forma rápida, eficiente y coherente. Cuenta con un editor RAML y una consola in- corporada, RAMLAPICONSOLE, que muestra y permite interactuar con la documentación así como generar solicitudes al API. Ambas han sido desarrolladas por Mulesoft y pueden ser descargadas desde GitHub.
Bajo las mismas condiciones que las anteriores podemos encontrar RAMLAPINOTEBOOK que posi- bilita un espacio de trabajo para Javascript scripting, con persistencia que permite probar y explorar las API, incluso de forma combinada, para conformar casos de uso y cualquier tipo de secuencia de solicitu- des encadenadas.
Al igual que ocurre con Swagger, aunque con un set de opciones mucho más reducido, la especi- ficación se puede emplear para generar código de cliente para su consumo y el soporte para el servidor del servicio. De igual forma al anterior, Postman [5] permite la importación de la especificación de un API descrito en RAML.
Existen otras utilidades que permiten generar documentación de forma estática para distintos le- guajes y frameworks como JAX-RS, PHP, etc. y en distintos formatos, html, pdf, wiki, etc.