Tag: Web

Buenas Prácticas para el Buen Diseño de una API RESTful

Según pasa el tiempo y vas haciendo servicios que tienen que escalarse e integrarse con otros servicios, te vas dando cuenta de lo necesario que es un buen diseño o por lo menos de un diseño mínimamente bien pensando y ejecutado que cumpla una serie de requisitos mínimos. Ésta es la idea que pretendo transmitiros, pero antes os ubico un poco.

En la entrada de Linkero – Creación de APIs RESTful en Python os presenté el framework Linkero que permitía montar APIs RESTful, y se presentaba junto con un ejemplo a forma de iniciación en las mismas.  En este entrada voy presentar una serie de recomendaciones, que pueden considerarse beunas prácticas, y que debéis tener en cuenta para asegurar un buen diseño de vuestras APIs RESTful.

El concepto subyacente de una API RESTful es la de dividir la estructura de la API en recursos lógicos, montados sobre una URL, que nos permitan acceder a información o datos concretos usando métodos HTTP como POST, GET, PUT y DELETE para operar con los recursos. Estos métodos son equiparables a las operaciones CRUD (Create, Read, Update, Delete) de las bases de datos. Aclarado esto, empecemos con las recomendaciones.

 

Usar nombres pero no verbos


Por cuestiones de mejor comprensión y legibilidad de la semántica de la API, usa sólo nombres para toda su estructura.

Recurso POST
create
GET
read
PUT
update
DELETE
/cars Crea un nuevo coche Devuelve la lista de coches Actualización en bloque de coches Borrar todos los coches
/cars/711 Método no permitido (405) Devuelve un coche específico Actualiza un coche específico Borra un coche específico

No usar verbos como:

/getAllCars
/createNewCar
/deleteAllRedCars

La propia semántica que compone la URL, junto con el método  HTTP usado (POST, GET, PUT, DELETE), permite prescindir de verbos como “create”, “get”, “update” y “delete”.

 

Métodos GET y los parámetros de consulta no deben alterar el estado


Usa los métodos POST, PUT o DELETE para cambiar los estados de los recursos, en vez de hacerlo con el método GET o un petición con parámetros de consulta. Para algo tienes 3 métodos que te permiten hacer eso 😉 .

Esto es lo que no se debería hacer:

GET /users/711?activate
GET /users/711/activate

Es mucho mejor hacer esto:

PUT /users/711/activate

o esto:

POST /users/711/activate

Cuál usar dependerá del diseño de la base de datos o la lógica con la que se estructura el almacenamiento de la misma.

 

Usar nombres en plural


No mezcles nombres en singular con nombres en plural. Hazlo simple y mantén los nombres en plural.

En vez de usar:

/car
/user
/product
/setting

Usa el plural:

/cars 
/users 
/products 
/settings

El uso del plural te permitirá posteriormente hacer operaciones del tipo:

/cars/<id> 
/users/<id> 
/products/<id> 
/settings/<name>

 

Usar subrecursos para establecer relaciones


Si un recurso está relacionado con otro, usa subrecursos montados sobre la estructura de la URL.

GET /cars/711/drivers/ Devuelve una lista de conductores para el coche 711
GET /cars/711/drivers/4 Devuelve el conductor #4 para el coche 711

 

Usar cabeceras HTTP para la serialización de formatos


Tanto la parte cliente como la del servidor, necesitan saber en qué formato se están pasando los datos para poder comunicarse. Lo más sencillo es especificarlo en la cebecera HTTP.

Content-Type: Define el formato de la petición.
Accept: Define la lista de formatos aceptados en la respuesta.

 

Usar HATEOAS


El uso de HATEOAS (Hypermedia as the Engine of Application State) es un diseño que nos permite incluir el principio de hipervínculos de manera similar a la navegación web, lo que nos permite una mejor navegación por la API.

En este ejemplo la respuesta en formato JSON nos devuelve junto con la información del equipo con id 5000, una serie de referencias a recursos relacionados, como pueden ser el estadio del equipo o sus jugadores. Normalmente se suele agrupar todas las referencias dentro de una propiedad o atributo llamada “links“.

{
    "links": [{
        "rel": "self",
        "href": "http://localhost:8080/soccer/api/teams/5000"
    }, {
        "rel": "stadium",
        "href": "http://localhost:8080/soccer/api/teams/5000/stadium"
    }, {
        "rel": "players",
        "href": "http://localhost:8080/soccer/api/teams/5000/players"
    }],
    "teamId": 5000,
    "name": "Real Madrid C.F.",
    "foundationYear": 1902,
    "rankingPosition": 1
}

Este tipo de diseño está pensado para la longevidad del software y la evolución independiente, ya que frecuentemente en la arquitectura de sistemas y servicios, es a corto plazo lo que más suele fallar.

 

Proveer filtrado, ordenación, selección de campos y paginación para colecciones


 

Filtrado

Utilizar un parámetro de consulta único para todos los campos o un lenguaje de consulta formalizado para filtrar.

GET /cars?color=red Devulve una lista de coches rojos
GET /cars?seats<=2 Devuelve una lista de coches con un máximo de 2 plazas

 

Ordenación

Permitir ordenación ascendente o descendente sobre varios campos

GET /cars?sort=-manufactorer,+model

En el ejemplo se devuelve una lista de coches ordenada con los fabricantes de manera descendiente y los modelos de manera ascendente.

 

Selección de campos

Permitir la selección de unos pocos campos de un recurso si no se precisan todos. Dar al consumidor de la API la posibilidad de qué campos quiere que se devuelvan, reduce el volumen de tráfico en la comunicación y aumenta la velocidad de uso de la API.

GET /cars?fields=manufacturer,model,color

En el ejemplo se pide la lista de coches, pero pidiendo sólo los campos de “fabricante“, “modelo” y “color“.

 

Paginación

Uso de “offset” para establecer la posición de partida de una colección y “limit” para establecer el número de elementos de la colección a devolver desde el offset. Es un sistema flexible para el que consume la API y bastante extendido entre los sistemas de bases de datos.

GET /cars?offset=10&limit=5

En el ejemplo se devuelve una lista de coches correspondiente a los coches comprendidos de la posición 10 a la 15 de la colección.

Para devolver al consumidor de la API el número total de entradas se puede usar la cabecera HTTP  “X-Total-Count” y para completar la información proporciona, por ejemplo, devolver los enlaces a la página previa y siguiente, entre otros, usando la cabecera HTTP “Link“.

Link: <http://localhost/sample/api/v1/cars?offset=15&limit=5>; rel="next",
<http://localhost/sample/api/v1/cars?offset=5&limit=5>; rel="prev",
<http://localhost/sample/api/v1/cars?offset=50&limit=3>; rel="last",
<http://localhost/sample/api/v1/cars?offset=0&limit=5>; rel="first",

Como alternativa es posible usar HATEOAS, como ya he comentado anteriormente.

 

Versionar la API


Es muy recomendable, tirando a obligatorio 😉 , el poner versión de API y no liberar APIs sin versión. Usa un simple número para especificar la versión y no uses un versionado tipo semver del tipo 1.5.

Si se usa la URL para marcar la versión, pon una “v” precediendo el número de versión.

/blog/api/v1

Es la forma más sencilla y eficaz de asegurar la compatibilidad en el versionado de la API. Especificarla como parámetro o en la petición y/o en la respuesta, conlleva el aumento del tráfico y el  coste de  computación, al tener que existir lógica para discriminar las distintas versiones soportadas sobre una misma URL.

 

Manejar errores con código de estado HTTP


Es difícil trabajar con una API que ignora el manejo de errores, por no decir imposible 😉 . La devolución de un código HTTP 500 para cualquier tipo de error o acompañado de una traza de error del código del servidor no es muy útil, además de que puede ponernos en peligro ante una vulnerabilidad que un atacante quisiera explotar.

 

Usar códigos de estado HTTP

El estándar HTTP proporciona más de 70 códigos de estado para describir los valores de retorno. En general no los utilizaremos todos, pero se debe utilizar por lo menos un mñinimo de 10, que suelen ser los más comunes:

Código Significado Explicación
 200  OK  Todo está funcionado
 201  OK  Nuevo recurso ha sido creado
 204  OK  El recurso ha sido borrado satisfactoriamente
 304  No modificado  El cliente puede usar los datos cacheados
 400  Bad Request  La petición es inválida o no puede ser servida. El error exacto debería ser explicado en el payload de respuesta
 401  Unauthorized  La petición requiere de la autenticación del usuario
 403  Forbidden  El servidor entiende la petición pero la rechaza o el acceso no está permitido
 404  Not found  No hay un recurso tras la URI
 422  Unprocessable Entity  Debe utilizarse si el servidor no puede procesar la entidad. Por ejemplo, faltan campos obligatorios en el payload.
 500  Internal Server Error  Los desarrolladores de APIs deben evitar este error. Si se produce un error global, el stracktrace se debe registrar y no devolverlo como respuesta.

 

Usar el payload para los errores

Todas las excepciones deben ser asignadas en un payload de error. A continuación se muestra un ejemplo de cómo podría verse un payload de error en formato JSON:

{
  "errors": [
   {
    "userMessage": "Sorry, the requested resource does not exist",
    "internalMessage": "No car found in the database",
    "code": 34,
    "more info": "http://dev.mascandobits.es/blog/api/v1/errors/12345"
   }
  ]
}

 

Permitir la sustitución del método HTTP


Algunos proxys sólo admiten métodos POST y GET. Para que una API RESTful funcione con estas limitaciones, la API necesita una forma de sustituir el método HTTP.

Una opción es utilizar la cebecera HTTP “X-HTTP-Method-Override” para sobrescribir el método POST y así personalizar la petición POST para que cumpla, por ejemplo, una operación DELETE.

X-HTTP-Method-Override: DELETE

 

Espero que esta concisa guía os permita realizar APIs RESTful con un mejor diseño, o mejorar aquellas que ya tengáis desarrolladas, eso sí generando una nueva versión de la API 😉 .

 

Simple RFC1738 Encoder – Codificación de una URL

La Informática e Internet es una piña de estándares que muchas veces a los desarrolladores nos son transparentes. Esto provoca que habitualmente no nos formulemos la pregunta de cómo se codifica, se procesa y se manda una dato, ya que existen funciones de alto nivel que nos resuelven dicha problemática o simplemente se realiza de manera transparente al desarrollador mediante un Framework o Librería.

¿Alguna vez te has preguntado cómo se codifican los caracteres que escribes? La verdad es que esto de la informática nació en los Estados Unidos y su Silicon Valley. Esto hace obvio que las codificaciones se pensaron para el inglés.

Con el tiempo la informática se extendió hasta su uso normalizado que tenemos hoy en día. El problema que tuvimos los de habla latina era que la codificación de base era UTF-8 y no incluía nuestros caracteres latinos, tales como: tildes, signos de exclamación e interrogación en la apertura, letra ñ … para caracteres codificados con 1 byte. Esto hacía necesario usar 2 bytes para codificar los caracteres latinos, ya que con 1 byte los caracteres incluidos son los de US-ASCII, subconjunto con un total de 128 caracteres correspondientes a las primeras posiciones de la tabla ASCII (American Standard Code for Information Interchange).

UTF-8 es un formato de codificación de caracteres Unicode e ISO-10646. La necesidad de usar 2 bytes para codificar caracteres latinos hace que la codificación en términos de consumo de espacio sea mayor, siendo necesario usar el doble de espacio (16 bits) si estamos codificando en algún idioma con caracteres latinos. A tal efecto se creó ISO-8859 y la derivación concreta ISO-8859-1 que es la norma de la ISO que define la codificación del alfabeto latino, incluyendo los diacríticos (como letras acentuadas, ñ, ç), y letras especiales (como ß, Ø). Esta codificación permite que dichos caracteres latinos se codifiquen en 8 bits, permitiendo la codificación del rango de los 128 primeros caracteres de la tabla ASCII y otros 128 caracteres más para lo que se denomina el conjunto de códigos extendidos de la tabla extendida ASCII. Puedes echarle un ojo a dicha tabla en:

https://github.com/RDCH106/Simple-RFC1738-Encoder#ascii-code—the-extended-ascii-table

Esta introducción que espero que haya servido para aclarar ciertos conceptos, sirve como base para la segunda parte que paso a explicar en las siguientes líneas.

Una forma habitual de pasar información en peticiones HTTP, es mediante el uso de encolado de parámetros en la URL (Uniform Resource Locator). Esto nos permite comunicarnos con APIs de otros servicios y a la vez es la base de las APIs RESTful como la que presentaba en la entrada “Linkero – Creación de APIs RESTful en Python“.

Obviamente de nuevo tenemos una especificación para codificar las URLs que es la RFC-1738 de 1994 creada por Tim Berners-Lee, el inventor de World Wide Web. Dicha especificación define que sólo un reducido conjunto de caracteres puede usarse en las URLs, los cuales son:

  • A to Z (ABCDEFGHIJKLMNOPQRSTUVWXYZ)
  • a to z (abcdefghijklmnopqrstuvwxyz)
  • 0 to 9 (0123456789)
  • $ (Dollar Sign)
  • – (Hyphen / Dash)
  • _ (Underscore)
  • . (Period)
  • + (Plus sign)
  • ! (Exclamation / Bang)
  • * (Asterisk / Star)
  • ‘ (Single Quote)
  • ( (Open Bracket)
  • ) (Closing Bracket)

Para mapear el amplio rango de caracteres utilizados en todo el mundo en los 60 caracteres permitidos en una URL, se utiliza un proceso estándar de dos pasos:

  • Conversión de la cadena de caracteres, en una secuencia de bytes utilizando la codificación UTF-8.
  • Conversión de cada byte que no sea una letra o dígito ASCII a% HH, donde HH es el valor hexadecimal del byte.

Por ejemplo, la cadena: “Rubén“, sería codificada como: “Rub%C3%A9n

Este es el proceso que de manera estándar se usa y que puedes encontrar en funciones como encodeURI en Javascript o urlencode en PHP. Pero esto no quiere decir que no puedas usar ISO-8859 como codificación base y luego codificar la URL con RFC-1738, consiguiendo de esta forma trabajar sobre una base de caracteres que permite ciertos caracteres, que aunque se puedan codificar en UTF-8, resultan ilegibles. Por ejemplo, la cadena: “Rubén“, sería codificada como: “Rubén“. No se entiende, ¿verdad?

El uso de UTF-8 nos obliga siempre a codificar dos veces, mientras que si se asume la codificación  ISO-8859, sólo es necesario aplicar la RFC-1738. Veis por donde voy, ¿no? UTF-8 es un estándar que nos penaliza por no ceñirse nuestra grafía de las letras de nuestro alfabeto al conjunto de caracteres ingleses. A pesar de que podamos codificarlo luego de nuevo, se antoja un paso prescindible si directamente se asume ISO-8859 en cualquiera de sus variantes como base de codificación de los caracteres. En mi caso la ISO-8859-1. De esta forma la codificación con RFC-1738 queda con un único valor hexadecimal (perteneciente a la tabla ASCII extendida) para los caracteres ilegibles codificados con UTF-8. Esto además genera URLs más cortas al no tener que usar dos conjuntos de hexadecimales para un único caracter. Por ejemplo, la cadena: “Rubén“, sería codificada como: “Rub%E9n“.

Esta problemática me llevó a desarrollar Simple RFC1738 Encoder, al cual podéis acceder a su código desde la dirección del proyecto:

https://github.com/RDCH106/Simple-RFC1738-Encoder

En el proyecto se explica de manera más resumida lo presentado en esta entrada y se ofrece la posibilidad de probar la librería desde:

https://rawgit.com/RDCH106/Simple-RFC1738-Encoder/master/demo.html

En la demo se pueden probar los distintos ejemplos de codificación presentados durante la entrada como son la codificación UTF-8 y la codificación RFC-1738 con o sin UTF-8 como codificación base. Podéis comprobar los resultados con las tablas facilitadas en el README del proyecto:

https://github.com/RDCH106/Simple-RFC1738-Encoder/blob/master/README.md

El proyecto Simple RFC1738 Encoder pretende ofrecer la capacidad de codificar las URLs usando RFC-1738 pero sin la necesidad de codificar con UTF-8 como base, pudiendo usar cualquier otra codificación como las recogidas en ISO-8859.

Activación de XDebug en XAMPP para depuración con Netbeans

Uno de los problemas de desarrollar en PHP, es que se interpreta en el lado del servidor y lo que devuelve es la información procesada de la lógica de PHP. Esto nos lleva a la problemática de que es poco útil inundar de trazas  de PHP que escriban en el HTML resultante de vuelta, los estados concretos de las variables procesadas durante la ejecución de la lógica programada.

Esto nos obliga a poner algún tipo de servicio de depuración que nos interrumpa la ejecución del intérprete de PHP y nos mande la información del estado de ejecución de cada punto de ruptura o de parada (breakpoint) que queramos añadir.

Uno de los frameworks de depuración más extendidos es XDebug, que además de ofrecer capacidades de depuración (debugging) también  ofrece características de análisis de rendimiento (profiling). Este framework se integra muy bien con todos las soluciones de servidor PHP,  como es mi caso concreto de XAMPP y mi entorno de desarrollo integrado Netbeans.

Para integrarlo lo primero que tenemos que hacer es localizar el fichero de configuración “php.ini” que contiene la información de configuración del intérprete de PHP que se encuentra en el directorio “xampp/php“. Abrimos el fichero con un editor de texto cualquiera y buscamos la existencia de “[XDebug]” y descomentamos las siguiente líneas quitando el punto y coma de delante de cada línea para conseguir las siguiente configuración:

[XDebug]
zend_extension = php_xdebug.dll
xdebug.remote_enable = 1
xdebug.remote_handler = dbgp
xdebug.remote_host = localhost
xdebug.remote_port = 9000

En el caso de no estar todas las líneas añade las que falten y si no encuentras nada que te referencie a XDebug, añádelo. En las últimas versiones de XAMPP sigue estando incluido XDebug, pero no hay rastro de él en el fichero de configuración. No obstante comprueba que existe en el directorio “xampp/php/ext” la libería dinámicaphp_xdebug.dll“.

Si alguno le echa un ojo al resto del fichero “php.ini“, se dará cuenta que existen un apartado de extensiones dinámicas (Dynamic Extensions), donde se referencian otras librerías dinámicas del directorio “xampp/php/ext“, cargadas con  “extension=“, en vez de “zend_extension=“. Esto es debido a que se carga usando el motor Zend. Si no lo respetáis, no os funcionará a pesar de que PHP os lo reconozca.

Para que la configuración tenga efecto guardamos el fichero y reniniciamos Apache si estaba ya funcionando. Si todo está correcto, entrando en la siguientes direcciones:

… deberíamos poder encontrar XDebug y poder ver toda la configuración.

php_xdebug

Ahora vayamos a Netbeans, quien por defecto ya viene con XDebug preconfigurado. En “Herramientas–>Opciones–>PHP–>Debugging“, comprobamos que “Debugger Port” sea el 9000 (el que configuramos en el fichero php.ini) y desmarcamos, si lo estuviera, la opción “Stop at First Line para que no entre en modo depuración en la primera línea del proyecto, sino cuando encuentra un breakpoint.

netbeans-php-debugging-config

Ahora si marcamos en cualquier parte del código con un breakpoint y lanzamos el proyecto en modo depuración netbeans-debug, la ejecución parará en el breakpoint marcado, pudiendo continuar la ejecución paso a paso si lo necesitásemos, supervisando la lógica y valores tomados durante la ejecución.

xdebug_break_point

Como habéis podido ver, el depurado XDebug configurado en XAMPP  e integrado con Netbeans, resulta de los más útil, dotándonos de una herramienta de depuración perfecta para trabajar en nuestros proyectos de PHP.

Linkero – Creación de APIs RESTful en Python (parte 1)

Según vas cogiendo experiencia como desarrollador de software te vas dando cuenta del verdadero significado de “No reinventar la rueda“. Debido muchas veces a la falta de tiempo, es casi obligatorio buscar soluciones desde las que partir, o buscar integraciones de software que permitan alcanzar el objetivo marcado.

No obstante la mayoría se suele quedarse ahí y se contentan con reutilizar “piezas”. El siguiente paso lógico y racional para ahorrar trabajo, pasa por diseñar. Por pensar y configurar un diseño que sea lo más generalista posible para que abarque el mayor número de casos de uso. Esta parte de diseño (y preferiblemente buen diseño) no suele ser frecuente entre desarrolladores, ya que suele implicar el gasto de más tiempo para ahorrarlo en un futuro. Debido a eso suele ser complicado trasladar a la dirección o al jefe inmediatamente superior y responsable del desarrollo, la necesidad de invertir más tiempo en un desarrollo para ahorrarlo en un futuro.

Hoy os traigo un caso de esos, en los que se juntan “piezas” y se refuerzan con un diseño para conformar una librería que ayude a un desarrollo más ágil, sujeto a un diseño flexible. Su nombre es Linkero:

https://github.com/RDCH106/linkero

link_slash

Linkero es un framework que permite la creación de manera sencilla de APIs RESTful para peticiones externas. Esta desarollado en Python y su diseño hace hincapié en los siguientes puntos:

  • Propósito general –> Se puede usar para cualquier tipo de API RESTful
  • Modular –> Se pueden agregar las API como si de módulos se tratasen quedando separadas del core de Linkero
  • Escalable –> Se pueden añadir nuevas APIs
  • Seguro –> Permite autenticar las peticiones por usuario y contraseña o mediante token de seguridad
  • Sencillo –> La codificación de las APIS y su securización es fácil de implementar.

La verdad es que originalmente el nombre de Linkero venía de link (unión en inglés) y el sufijo ero (que viene a significar “el  que”), es decir, el que une. Con el tiempo le vi una segunda connotación que tenía relación con el personaje Link de “The Lengedn of Zelda” y el juego de palabras link + hero (unión + héroe).

Como desde hace un tiempo, pienso que el Open Source es una vertiente totalmente Win&Win, decidí liberar el código fuente cuando consideré que el código estaba lo suficientemente maduro para empezar a recoger aportes. Uno de los mejores puntos que tiene el Open Source es su escrutinio público que ayuda a revelar fallos y la aportación de mejoras por otros usuario o empresas que usen dicho código y hayan implementado mejoras. Por contra, existe muchos usuario y sobre todo empresas que usan Open Source, pero no devuelven absolutamente NADA, si la licencia que acompaña el software lo permite. Es lícito hacerlo, no obstante la contrapartida real, es que tras cada mejora en el proyecto principal que se quiera integrar, resulta exponencialmente más difícil, ya que la mejoras introducidas no liberadas, pueden provocar divergencias con las actualizaciones y el diseño oficial.

Desde hace tiempo tengo la convicción de que en software, no se debería vender software tal cual, sino servicio, vender soluciones en vez de productos. Un mismo software o producto puede aplicarse para proveer diversidad de soluciones a problemas distintos e integrarse con otras tantas soluciones diferentes para solventar retos mayores. Esto es una visión totalmente personal ya que como Ingeniero Informático, lo he podido comprobar. El software es una herramienta. Yo proporciono soluciones a través de mi herramienta principal que es la creación de software y a su vez también uso software de terceros para proveer soluciones. Aclarada la visión personal y profesional de mi campo, volvamos al tema principal de la entrada 😉 .

Linkero cuenta con el siguiente diseño general:

linkero_general-scheme_800x600

Y hace uso de las siguientes librerías:

El esquema conceptual de dependencias refleja como únicas dependencias para crear una aplicación, el uso de Linkero y el uso de todas las APIs desarrolladas para Linkero que se quieran incluir. Linkero a su vez hace uso de las anteriormente citadas librerías. A su vez hace falta un “MAIN” que cargue las APIs y las ponga en funcionamiento con Linkero

Teniendo en mente el esquema puedes instalarte Linkero siguiendo las indicaciones de la Wiki:

https://github.com/RDCH106/linkero/wiki/instalacion

Si has seguido todos los pasos de la sección de instalación deberías poder probar Linkero usando el ejemplo testBasicAPI ejecutando el “testBasicAPI_main.py” desde Python.  Este ejemplo es una versión simplificada que a efectos ilustrativos no incluye temas de autenticación. Si analizamos el ejemplo, obtendremos la estructura mínima para desarrollar una API con Linkero que no requiera de autenticación.

Primero se importa el core de Linkero:

import core.linkero as linkero

A efectos demostrativos se crea una estructura de tareas pendientes:

# TODOS Data
TODOS = {
    'todo1': {'task': 'build an API'},
    'todo2': {'task': '?????'},
    'todo3': {'task': 'profit!'},
}

Se define una función que maneje las peticiones sobre objetos no existentes y se genera un objeto “parser” para las peticiones, al que se le añade el argumento “task”:

def abort_if_todo_doesnt_exist(todo_id):
    if todo_id not in TODOS:
        linkero.abort(404, message="Todo {} doesn't exist".format(todo_id))

parser = linkero.reqparse.RequestParser()
parser.add_argument('task')

Posteriormente definimos los métodos que nos permitan manejar los items de las tareas por separado (métodos GET, DELETE, PUT). Los métodos GET y DELETE hacen  uso del método “abort_if_todo_doesnt_exist” para comprobar que se puede realizar la acción sobre el item específico y PUT hace uso del objeto “parser” para obtener el valor a introducir de la petición:

# Todo
# shows a single todo item and lets you delete a todo item
class Todo(linkero.Resource):
    def get(self, todo_id):
        abort_if_todo_doesnt_exist(todo_id)
        return TODOS[todo_id]

    def delete(self, todo_id):
        abort_if_todo_doesnt_exist(todo_id)
        del TODOS[todo_id]
        return '', 204

    def put(self, todo_id):
        args = parser.parse_args()
        task = {'task': args['task']}
        TODOS[todo_id] = task
        return task, 201

Es habitual ofrecer métodos que nos permitan manejar conjuntos de items. Por ello se definen métodos como pueden ser GET (obtener todas las tareas) o POST (incluir un grupo de tareas):

# TodoList
# shows a list of all todos, and lets you POST to add new tasks
class TodoList(linkero.Resource):
    def get(self):
        return TODOS

    def post(self):
        args = parser.parse_args()
        todo_id = int(max(TODOS.keys()).lstrip('todo')) + 1
        todo_id = 'todo%i' % todo_id
        TODOS[todo_id] = {'task': args['task']}
        return TODOS[todo_id], 201

Una vez definida los métodos que permiten operar con la API, se define un método “loadTestBasicAPI” que asocia un patrón de URL a los métodos definidos:

##
## Actually setup the Api resource routing here
##
def loadTestBasicAPI():
    linkero.api.add_resource(TodoList, '/todos')
    linkero.api.add_resource(Todo, '/todos/&lt;todo_id&gt;')

Con la API completamente definida sólo queda cargarla y ejecutarla con Linkero mediante un “main.py” (para nuestro ejemplo es el “testBasicAPI_main.py“). Para ello se importa el core de Linkero y nuestra API (paso 1 y 2), se carga la API con el método “loadTestBasicAPI” (paso 3) y se invoca el método “run” de Linkero (paso 4):

# 1) Linkero Core
import core.linkero as linkero

# 2) APIs developed to use with Linkero
import examples.testBasicAPI

# 3) Load desired APIs
examples.testBasicAPI.loadTestBasicAPI()

# 4) Run Linkero
linkero.run()

Con estos simples pasos es posible realizar una API RESTful, definiendo la interfaz de la misma y su lógica en cómodos ficheros que pueden ser cargados y lanzados por Linkero. En la segunda parte de esta entrada se ahondará en la securización de la API, así como los aspectos que no se han podido tratar en esta primera parte.