May 24th, 2012

Aplicaciones RESTful con Apache CXF (Parte 2/2).

Juan Pablo Warmerdam

En la primera parte de este articulo vimos  que aparecían, pero no los describimos, una serie de anotaciones que indican el método HTTP utilizado. Sin embargo no entramos en detalle en el porqué del uso de los mismo o como usar la anotación adecuada.  Debido a que en esta parte tienen una participación más relevante, vamos a revisarlos un poco.

Verbos de HTTP

En HTTP se definen nueve métodos (a veces llamados verbos) que indican la acción a ser ejecutada sobre un recurso en particular. A continuación veremos los más usados.

El método GET es el pedido de una representación sobre un recurso. La información se entrega con un conjunto de encabezados y una representación. El cliente nunca envía una representación en un método GET. Se considera, junto a HEAD,como un método seguro, ya que no provoca cambio en el servidor.

El método HEAD es lo mismo que en GET, solo que la información que se envía como respuesta solo incluye los encabezados.

El método PUT es una afirmación sobre el estado de un recurso. El cliente usualmente envía una representación del recurso en un PUT y el servidor trata de cambiar o actualizar el recurso de forma tal que su estado se corresponda con el que tiene la representación. El método PUT, junto al DELETE, se definen como métodos idempotentes, es decir, hacer múltiples request a una URL deberían tener el mismo resultado que hacer uno solo. Los métodos seguros, también se consideran idempotentes.

El método DELETE una afirmación que dice que el recurso ya no debe existir. El cliente nunca envía una representación en el método DELETE.

El método POST es el envío de información para crear un nuevo recurso,  modificar uno existente o las dos cosas a la vez. La representación enviada por método POST, describe el estado inicial del nuevo recurso.  El método POST, no es necesariamente idempotente y por lo tanto, enviar múltiples POST puede tener (y en general es así) efectos secundarios no deseados.

POST vs PUT

La creación/actualización de recursos se puede hacer por medio del método POST, PUT o de ambos. La diferencia fundamental entre ambos métodos se ve reflejada en el significado de la URL. La URL en un método POST hace referencia al recurso que se encargara de administrar la entidad enviada. Ese recurso puede ser un proceso que acepte información, un Gateway hacia otro protocolo, etc. En cambio, la URL en un método PUT representa a la entidad en sí misma que debe ser actualizada o creada sin intermediarios.

Ahora que hemos repasado los diferentes métodos HTTP, vamos a seguir con nuestro ejemplo para la creación/utilización de servicios REST con CXF.

Pasaje de parámetros

La anotación @PathParam se utiliza para mapear las variables contenidas en el path a parámetros de un método, por ejemplo:


@Path("/customer/{id}")
public class CustomerService {

@PUT
@Path("{name}")
public Response updateCustomer(@PathParam("id") Long id, @PathParam("name") String name) {
...
}
}

En este caso, la variable id del la anotación de la clase, es mapeada a un parámetro de tipo Long, mientras que la variable name que aparece en el método, es mapeada a un parámetro de tipo String.

Tambien se soportan las anotaciones @QueryParam, @HttpHeader, @MatrixParam, @FormParam y @CookieParam y su eleccion dependera del metodo usado y de la ubicacion de los parametros. Los parametros pueden ser de tipo String o de cualquier tipo que posea un constructor estatico por medio del método valueOf(String s).

Sub-recursos

Un método de una clase/recurso que posea la anotación @Path y no posea una de método HTTP (como GET, POST, etc.) se considera como un sub-recurso. Los localizadores de sub-recursos se utilizan para resolver path hacia objetos que están mucho más adentro del árbol de servicios.

En nuestro ejemplo, el método getOrder, es un sub-recurso.

 


@Path("/customerservice/")
public class CustomerService {

@Path("/orders/{orderId}/")
public Order getOrder(@PathParam("orderId") String orderId) {
......
}
}

@XmlRootElement(name = "Order")
public class Order {
private long id;
private Items items;

public Order() {
}

public long getId() {
return id;
}

@GET
@Path("products/{productId}/")
public Product getProduct(@PathParam("productId")int productId) {
......
}

@Path("products/{productId}/items")
public Order getItems(@PathParam("productId") int productId) {
return this;
}

@GET
public Items getItems() {
......
}

}

 

Un pedido HTTP GET a http://localhost/customerservice/orders/223/products/323 produce que el método getOrder sea ejecutado. Si el recurso Order, cuyo id es 223, es encontrado, dicho recurso será utilizado para resolver el recurso Product. Eventualmente, un Product de id 223 que pertenezca a un Order de id 223 será devuelto.

Manejo de excepciones

Para devolver excepciones, uno puede o devolver una excepción no chequeada genérica o devolver un objeto javax.ws.rs.core.Response con un código de error. Esta segunda opción parece ser la más adecuada cuando se trabaja con JAX-RS.

Por ejemplo:

 


@Path("/customerservice/")
public class CustomerService {

@PUT
@Path("/customers/{id}")
public Response updateCustomer(@PathParam("id") Long id, Customer customer) {
return Response.status(errorCode).build();
}

@POST
@Path("/customers")
public Customer addCustomer(Customer customer) {
throw new WebApplicationException(errorCode);
}

}

 

 

Es posible cubrir casi todas las situaciones con los siguientes códigos de error:

  • 200 (OK) -  Todo bien.
  • 400 (Bad Request) -  Hay un problema del lado del cliente.
  • 500 (Internal Server Error) – Hay un problema del lado del servidor. Este error se puede usar también para denegar acceso sin revelar que la causa del rechazo se debe a permisos/credenciales.
  • 404 (Not Found) / 410 (Gone)  – Se envía cuando el cliente trata de acceder a un recurso que el server no encuentra. El error 404  se envía cuando el server no tiene idea de que recurso buscar, el 410 se envía cuando aunque sabe de que se trata, no lo encuentra/existe.
  • 409 (Conflict) – Indica que se intenta poner al recurso en un estado inconsistente o inaceptable. Por ejemplo, cuando se trata de borrar un elemento sin eliminar las relaciones que pueda tener.

 

Referencias:

http://cxf.apache.org/

http://en.wikipedia.org/wiki/Representational_state_transfer

http://cxf.apache.org/docs/jax-rs-basics.html

http://www.infoq.com/articles/rest-introduction

http://tomayko.com/writings/rest-to-my-wife

http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.6

Dejar un comentario