====== 10.1 REST ====== Hay libros enteros que hablan sobre REST así que en esta unidad solo vamos a ver lo principal de REST sin entrar en detalle finos. Aun así, lo que vamos a ver creo que es suficiente para gran cantidad de aplicaciones por lo que no debemos pensar que nos quedaremos cortos. Para saber hasta donde vamos a ver de REST podemos usar el modelo de madurez creado por Leonard Richardson y explicado por Martin Fowler en [[http://martinfowler.com/articles/richardsonMaturityModel.html|Richardson Maturity Model]]. Este modelo explica que hay 4 niveles de madurez para usar REST que son ((Esta explicado de forma coloquial para que se entienda)): * Nivel 0: Usar HTTP para tu comunicación pero nada mas de lo que ofrece el protocolo. * Nivel 1: Usar las URL siguiendo el formato de REST * Nivel 2: Usar los códigos, verbos , etc. de HTTP * Nivel 3: Usar hiperenlaces para descubrir los servicios REST. Es lo que se llama [[http://en.wikipedia.org/wiki/HATEOAS|HATEOAS]]. Aquí vamos a explicar los niveles 1 y 2 ((El nivel 0 sería lo que ya hemos usado del protocolo HTTP en nuestras llamadas AJAX)). ====== HTTP ====== Podríamos decir que REST es usar toda la potencia de HTTP en nuestras propias aplicaciones. Así que es necesario saber algo de HTTP para poder explicar REST. HTTP como casi todo en informática lo podemos ver como una caja a la que le enviamos datos y nos retorna datos. Lo importante de HTTP es saber que tipos de datos se envían y que tipos de datos se responden. A primera vista podemos pensar que lo que se envía es una URL y lo que se retornan son los datos. Pero también hay que tener en cuenta los códigos de estado en la respuesta como por ejemplo el 404 "No encontrado". Otra dato es si enviamos por POST o GET, etc. Por ello vamos a describir los datos que enviamos y recibimos por HTTP ((Solo los relevantes como desarrolladores de aplicaciones)). ===== Datos enviados ===== Los datos que se envían es una petición HTTP son: * La URI del recurso que se pide. * El método HTTP * Las cabeceras HTTP. Hay gran cantidad de cabeceras pero su formato es siempre el nombre de la cabecera y su valor. * El cuerpo de la petición con los datos del usuario. Por ejemplo datos en formato JSON o datos en formato XML. ===== Datos recibidos ===== Los datos que se reciben en una petición HTTP son: * El código de estado * Las cabeceras HTTP de rspuesta. * El cuerpo de la respuesta con los datos para el usuario. Por ejemplo la página HTML, datos en formato JSON o datos en formato XML. ====== REST ====== REST es una arquitectura para aplicaciones en red similar a [[http://es.wikipedia.org/wiki/Simple_Object_Access_Protocol|SOAP]] o [[http://es.wikipedia.org/wiki/XML-RPC|XML-RPC]] pero se diferencia de ellos en su sencillez y que utiliza todas las características que puede de de HTTP en vez de reinventarse lo que ya tiene HTTP. Esta última característica yo creo que es la que mejor explica que es REST: Si algo ya existe en HTTP y REST siempre funciona bajo HTTP, ¿porque no usar entonces todo lo que ofrece HTTP?. Por lo tanto cuando necesitemos algo en nuestra aplicación siempre debemos preguntarnos , ¿como resuelve este problema ya el protocolo HTTP? Y usarlo en vez de crear nuestra solución. Hablando de una forma sencillo lo que nos dice es como debemos comunicarnos desde la página web ((o desde una aplicación movil ,desde una aplicación de escritorio, desde otro servidor, etc.)) con el servidor especificando cosas como: * Las operaciones a realizar * La Estructura de la URI * Tratamiendo de errores * El formato de los datos * El estado de la aplicación * Cache * Etc. ===== Las operaciones a realizar ===== Sabemos que HTTP tiene operaciones como GET y POST, pero tiene algunas mas que vamos a explicar ahora mismo ((Realmente nos vamos a dejar alguna)). Vamos a ver 4 método HTTP que coinciden con los 4 métodos de un CRUD o con operaciones de SQL ^ Método HTTP ^ Descripción ^ Metodo CRUD ^ Metodo SQL ^ | GET | Este método HTTP lo usaremos para cuando queremos leer datos del servidor | Read | SELECT | | POST | Este método HTTP lo usaremos para añadir datos al servidor | Crear | INSERT | | PUT | Este método HTTP lo usaremos para actualizar ((realmente es actualizar o insertar pero en este curso por simplificar, el POST solo actualizará)) datos del servidor | Update | UPDATE | | DELETE | Este método HTTP lo usaremos para borrar datos del servidor | Delete | DELETE | Así por ejemplo, para borrar un seguro médico del servidor ya no usaremos un GET con una url del estilo http://miapp.com/seguros/borrar/seguromedico sino que es **obligatorio** que el método sea DELETE. Y lo mismo con el resto de métodos. ===== La Estructura de la URI ===== Ya tenemos las operaciones, ahora pasemos al formato de la URI. La URI es como la URL pero le hemos quitado la parte inicial de la URL ya que la parte inicial depende de donde instalemos la aplicación. Aunque no forma parte del estándar de REST , personalmente las URL me gusta hacer que empiecen todas por "/api" ya que así tengo un espacio para distinguirlo de las peticiones HTML y por otro lado REST realmente lo que crea es un nuevo API pero a nivel de la web. Por ello todas las URI empezarán por /api Vamos a ver las características que deben tener las URI * La URI no debe contener la acción. Así por ejemplo no debería ser ''/api/seguromedico/delete'', para indicar la acción ya está el método HTTP. Es decir no puede hacer verbos en la URI como borrar, copiar , imprimir, cerrar, etc. * La URI no debe contener el formato de los datos que solicitamos. Es decir que no puede acabar por ".pdf" ni por ".json" ni ".xml" , etc. Y ¿como se soluciona si queremos algo en un formato distinto? Pues de la misma manera que lo hace el navegador, con la cabecera ''Accept''. Esta cabecera indica el formato que queremos que nos envíe el servidor. Por ejemplo si incluimos la cabecera ''Accept: application/json'' significará que lo queremos en formato JSON. * La propia URI hace referencia al recurso sin necesidad de parámetros. Por ejemplo si queremos el seguro médico con idSeguro=34, la URI no debe ser ''/api/seguromedico?idSeguro=34'' sino que lo correcto es ''/api/seguromedico/34''. * Las URI pueden seguir una jerarquia, por ejemplo ''/api/banco/4567/sucursal/67''. Es decir queremos la sucursal 67 pero del banco 4567. * Para las búsquedas o filtrado si que se permiten los parámetros. Por ejemplo , la URI ''/api/seguromedico/?nombre=Juan&ape1=Cano'' Con todas estas reglas vamos a ver las URI que se suelen usar en una aplicación. Vamos a usar como ejemplo la entidad "Usuario", es decir la URI que usaríamos para hacer un CRUD de la Tabla o Entidad "Usuario". ^ Descripción ^ URL ^ Método HTTP ^ JSON Enviado ^ JSON Retornado ^ | Leer un usuario | ''/api/Usuario/{idUsuario}'' | GET | Ninguno | Usuario leido | | Buscar usuarios | ''/api/Usuario/?columnaBusqueda1=valor1&columnaBusqueda2=valor2&....'' | GET | Ninguno | Array de usuarios | | Añadir un usuario | ''/api/Usuario'' | POST | Usuario a insertar | Usuario insertado | | Actualizar un usuario | ''/api/Usuario/{idUsuario}'' | PUT | Usuario a actualizar | Usuario actualizado | | Borrar un usuario | ''/api/Usuario/{idUsuario}'' | DELETE | Ninguno | Ninguno | Donde pone ''{idUsuario}'' se subtituiría por el id del usuario. El "JSON Enviado" es el JSON que se debe enviar con los datos al hacer esa petición. Como podemos ver solo se envía al insertar o al actualizar. Es decir es el JSON del usuario a insertar o el JSON con los nuevo datos del usuario a modificar. El "JSON Retornado" es lo que nos retornará el servidor. Como vemos nos retorna un JSON con los datos en todos los casos excepto en el borrado, y no lo hace ya que no existe ningún dato a retornar ya que lo hemos borrado. Son realmente el JSON que esperamos con los datos de los usuarios al hacer la petición. Puede parecer extraño que en el insert y el update se retornen los datos en formato JSON con el usuario recién insertado o actualizado. Esto lo hago ya que al insertar o actualizar puede que el servidor haya modificado los datos. Un clásico ejemplo es poner la fecha de creación/modificacion o poner el id de la clave primaria. Por ello lo retornamos para que el cliente tenga toda la información. Esta tabla que acabamos de ver para mi es lo mas importante de REST ya que estamos viendo los métodos que deberemos implementar en nuestros controladores de Java, las URI asociadas, los datos de entrada y salida, etc.Y lo tanto hay que entenderla perfectamente. Esta tabla es una posible solución siguiendo las características que deben tener las URI en REST. Pero realmente REST no nos dice exactamente como deben ser las URI sino que nos dice las características que deben seguir dichas URI. Aun así esta solución o soluciones muy parecidas a esta son las que se suelen usar en los proyectos. Aunque repito que las puedes modificar según tu proyecto. Una posible modificación que vi en un proyecto real consistía en hacer que el update y el insert no retornaran el objeto completo actualizado o insertado. Y no lo retornaban para ahorra tiempo y ancho de banda. Solo se retornaba en id del objeto recién insertado. Luego si hacía falta todos los datos , cosa que no solía necesitarse, se podían obtener con una llamada a ''GET'' extra. ===== Tratamiendo de errores ===== Como ya podemos imaginar la gestión de errores la tenemos que hacer siguiendo los códigos de estado de HTTP. En la siguiente imagen podemos ver los [[https://developer.yahoo.com/social/rest_api_guide/http-response-codes.html|códigos que usa Yahoo en su API de social]]: {{:unidades:10_servidor:yahoo_http_error_codes.png?nolink|}} Controlar todos estos códigos en la aplicación es un poco excesivo, así que nosotros vamos a simplificar el números de códigos que retornará nuestra aplicación. Primero empecemos con solo 3 códigos: * ''200 OK'': Si la petición ha sido realizada con éxito * ''500 Internal Server Error'': Si ha habido algún error interno en nuestro propio servidor. * ''400 Bad Request'': Si los datos enviados por el cliente no eran correctos. Normalmente son datos escritos por el usuario y que son erróneos. El siguiente código útil es ''204 No Content'', este lo deberíamos retornar en vez del ''200 OK'' cuando no retornemos ninguna dato. Por lo que debería retornarse al hacer un ''DELETE''. Los códigos ''401 Unauthorized'' y ''403 Forbidden'' los retornaría la parte de seguridad que no veremos en este curso. El código ''404 Not Found'' lo suele retornar el propio servidor si no encuentra la forma de procesar la petición y lo mismo pasa con el código ''405 Not Allowed'' que lo suele retornar automáticamente Spring ((El framework que vamos a usar para implementar la parte servidora en java)) si usamos un método HTTP con una URL que no soporta ese método. Así que resumiendo en nuestra aplicación solo deberíamos retornar los siguientes códigos: ^ Código ^ Nombre ^ Significado ^ | ''200'' | OK | Todo ha funcionado correctamente y retornamos los datos | | ''204'' | No Content | Todo ha funcionado correctamente pero **NO** retornamos datos ya que no es necesario. Se usa en el DELETE en el que no se retorna nada | | ''400'' | Bad Request | Hay errores en los datos que ha enviado el usuario. Se retornará un objeto ''List'' en formato JSON | | ''500'' | Internal Server Error | Error del servidor. Se produce cuando hay un error en el código. Se retorna la excepción que se ha producido | REST no dice nada sobre que datos retornar cuando hay algún problema como es en el caso del ''400 Bad Request'' y ''500 Internal Server Error''. En nuestra arquitectura REST hemos decidido hace los siguiente. En caso de ''500 Internal Server Error'' retornaremos un texto plano con la traza de la excepción que se ha producido en Java. Ya que lo normal de cuando hay un error es que sea debido a que se ha lanzado una excepción en Java. De esa forma podremos depurar que ha ocurrido. Esto por otro lado podría ser un fallo de seguridad ya que la traza podría contener información que ayudara a realizar un ataque. La solución a ésto es simplemente que haya en el servidor una variable que indique si retornamos la traza completa , solo el nombre de la excepción o un mensaje diciendo que ha habido un error. Esta variable la podríamos cambiar según estemos en desarrollo o en producción , etc. En caso del ''400 Bad Request'' retornaremos una lista de mensajes para el usuario. Esta lista suelen ser las validaciones que han fallado al intentar realizar la operación. En nuestra arquitectura usaremos un array de clases Java llamada ''BusinessMessage'' que retornaremos en formato JSON al cliente. La estructura de la clase ''BusinessMessage'' es la siguiente: public class BussinessMessage { private final String fieldName; private final String message; public BussinessMessage(String fieldName, String message) { this.fieldName = fieldName; this.message = message; } public String getFieldName() { return fieldName; } public String getMessage() { return message; } } Mas información sobre esta clase la puedes encontrar en mi curso de hibernate en [[http://cursohibernate.es/doku.php?id=unidades:07_arquitectura:02_excepciones&#el_codigo_de_bussinessexception|El código de BussinessException]] ===== El formato de los datos ===== Como ya dijimos al ver el formato de las URI, para indicar el formato en el que queremos que nos retornen los datos hay que usar la cabecera ''Accept''. Desde Angular no tenemos que preocuparnos por poner esta cabera ya que lo hace automáticamente para pedir los datos en formato JSON. Por otro lado cuando insertamos o actualizamos , estamos enviando datos en formato JSON, ¿Como le decimos al servidor que son en formato JSON? Usando la cabecera ''Content-Type: application/json''. Tampoco debemos preocuparnos en ponerla ya que AngularJS también lo hace por defecto. Al retornarnos el servidor los datos también incluirá en la respuesta otra cabecera ''Content-Type'' para indicar el formato de los datos que ha retornado. Vamos ahora a resumir las cabeceras que hay al hacer una petición y recibir la respuesta: * En la petición: * ''Accept'' : Para indicar el formato de los datos que queremos que nos retorne el servidor * ''ContentType'' : Para indicar el formato de los datos que le estamos enviando. * En la respuesta: * ''ContentType'' : Para indicar el formato de los datos que se está devolviendo. Como ya hemos dicho, en la petición no tendremos que preocuparnos de poner estas cabeceras ya que AngularJS ya lo hace pero en la respuesta nosotros deberemos desde Java indicar el ''Content-Type'' ===== El estado de la aplicación ===== El tema del estado de la aplicación en el servidor es muy sencillo de tratar en REST. Simplemente nunca hay estado en el servidor para cada cliente. Cada petición debe ser independiente de las demas y nunca guardar nada en la sesión del servidor. Aunque esto es la teoría , yo personalmente si que guardo en la sesión el usuario que ha entrado en el sistema aunque se podría crear una solución **similar** sin necesidad de guardar en el servidor nada usando [[https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/|Token-Based Authentication]]. ===== Cache ===== Al ser una petición REST como cualquier otra petición a una página web deberíamos tener en cuenta que las peticiones se pueden cachear en el navegador o en cualquier otro punto de la red. Por ello en general es adecuado indicar desde el servidor si la respuesta puede ser o no cacheada. ===== Otras características ===== Siguiente HTTP podríamos ver mas cosas como por ejemplo como hacer la paginación, como retornar solo ciertos campos , etc. Pero no los vamos a ver en este curso. ====== Referencias ====== * [[http://en.wikipedia.org/wiki/Representational_state_transfer|Wikipedia > REST]] * [[http://martinfowler.com/articles/richardsonMaturityModel.html|Richardson Maturity Model]] * [[https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/|Cookies vs Tokens. Getting auth right with Angular.JS]] * [[http://stackoverflow.com/questions/2001773/understanding-rest-verbs-error-codes-and-authentication|Understanding REST: Verbs, error codes, and authentication]]: Clásica pregunta sobre REST en stackoverflow * [[http://java.dzone.com/articles/restful-standard-resolved|RESTful Standard Resolved!]]: Resumen del formato de las URL en REST * [[http://rest.elkstein.org/|Learn REST: A Tutorial]]: Tutorial en inglés sobre REST * [[http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven|REST APIs must be hypertext-driven]]: Las API REST deben tener las URL a los recursos. * [[http://blog.2partsmagic.com/restful-uri-design/|REST-ful URI design]]: Como diseñar un buen API REST * [[http://elbauldelprogramador.com/buenas-practicas-para-el-diseno-de-una-api-restful-pragmatica/|Buenas prácticas para el diseño de una API RESTful pragmática]]