¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Jakarta EE
  3. Los servicios web REST
Extrait - Jakarta EE Desarrolle aplicaciones web en Java
Extractos del libro
Jakarta EE Desarrolle aplicaciones web en Java
1 opinión
Volver a la página de compra del libro

Los servicios web REST

Introducción

La plataforma Jakarta EE es un conjunto importante de tecnologías. Todas ellas satisfacen diferentes necesidades. Entre estas tecnologías, algunas son muy populares en la actualidad en el mundo del desarrollo web.

Se trata de:

  • La tecnología Jakarta RESTful Web Services (anteriormente, JAX-RS), en la versión 3.0. Proporciona una API Java para crear Services Web REST. El término JAX-RS se utilizará en lo sucesivo en este capítulo para hacer referencia a esta tecnología. 

  • La tecnología Jakarta WebSocket en su versión 2.0, proporciona una API Java para configurar la comunicación web basada en el protocolo WebSocket. Esta tecnología se presentará en el próximo capítulo de este libro. 

Introducción a los servicios web REST

1. Principios

El objetivo principal de la Web es proporcionar acceso a los recursos identificados por una URL (Uniform Resource Locator).

Estos recursos se representan muy a menudo como una página web, utilizando el lenguaje HTML. Pero estos recursos también se pueden devolver en otros formatos o tipos de medios (XML, PDF, imágenes, etc.). La cabecera de la petición Accept define el tipo de medios esperados por el cliente y la cabecera de la respuesta Content-Type define el tipo de medios realmente obtenidos. Para más información, consulte la sección Tipos de medios del capítulo Introducción a Jakarta EE.

La aplicación utilizada para ver estos recursos (muy a menudo un navegador) cambia de estado con la representación del recurso transferido. El acrónimo REST significa REpresentational State Transfer. Es un estilo de arquitectura centrado en los recursos. 

La lectura de información, como los deportes practicables dentro del complejo deportivo, se realiza de forma natural a través de una URL utilizando el protocolo HTTP y el método GET:

http://www.hacerdeporte.com/Deportes  
http://www.hacerdeporte.com/Deportes/14 

El primer ejemplo se utiliza para obtener la lista de deportes y el segundo ejemplo permite obtener el deporte identificado por el número 14.

¿Qué sucede si ahora queremos interactuar con esta lista...

Configurar el entorno de desarrollo

1. Elegir una implementación

La tecnología JAX-RS está disponible a través de varias implementaciones, incluidas las siguientes:

Esta lista no es exhaustiva. La implementación Apache CXF también se usa ampliamente, pero en la actualidad no es compatible con JAX-RS versión 3.0. El libro no pretende elegir una implementación frente a otra. Solo se va a describir cómo funciona la tecnología JAX-RS. Todos los ejemplos funcionarán en ambas implementaciones, a menos que se indique lo contrario.

2. Implementar el proyecto y las dependencias

El objetivo de este capítulo es comprender cómo funcionan los servicios web REST a través de un proyecto de ejemplo llamado Proyecto_REST.

 Comience creando un Gradle Project con las mismas características que en el primer capítulo.

 Complete el árbol de directorios para que tenga este aspecto:

images/06EP01N.png

 Añada un archivo llamado web.xml en el directorio src/main/webapp/WEB-INF, con contenido equivalente al del proyecto inicial (PrimerPROWeb). Asegúrese de cambiar el nombre del proyecto dentro de la etiqueta...

La especificación JAX-RS

1. Introducción

La presentación no pretende ser exhaustiva. Sin embargo, permite abordar los puntos esenciales que se deben entender para iniciar un proyecto con la especificación JAX-RS.

2. Funcionamiento general

La especificación JAX-RS describe cómo exponer los servicios web REST. Desde la versión 2.0, también existe la descripción de una API cliente. Con esta API, será más fácil crear una aplicación cliente escrita en Java que necesite llamar a servicios web REST. Se va a dedicar una sección a este punto llamada API cliente.

Volvamos a exponer los servicios web REST en el servidor. Cuando una petición de un recurso llega al servidor, seguirá un conjunto de pasos antes de obtener una respuesta para el cliente. A continuación, se muestra el diagrama que puede encontrar en el apéndice de la especificación oficial:

images/06EP03N.png

Este diagrama puede parecer complicado al principio, pero nos da una visión global del camino recorrido:

  • La petición (Request) llega al servidor, exponiendo los servicios web REST. A continuación, la implementación JAX-RS elegida administra la petición.

  • Los procesos representados por PreMatchContainerRequest Chain se corresponden con la ejecución del método filter() de clases que implementan la interfaz jakarta.ws.rs.container.ContainerRequestFilter. Estas clases...

La configuración de la aplicación

Tomcat 10 es un contenedor de servlets 5.0. Como tal, implementa el mecanismo de conectividad que permite descubrir durante el inicio qué elementos hay que cargar, como la implementación JAX-RS elegida, sin que el desarrollador necesite configurar nada. Basta con que la librería (en este caso, la implementación JAX-RS) proporcione una clase derivada de la clase ServletContainerInitializer. Esta clase es el punto de entrada para cargar y desencadenar la configuración de la implementación elegida. Para obtener más detalles sobre cómo funciona, puede leer el capítulo Annotations and pluggability de la especificación Java Servlet Specification, en su versión 5.0.

Ahora que este problema está resuelto, debemos configurar al menos la implementación JAX-RS. La configuración esencial consiste en asociar una URL raíz que permita que todas las URL que empiezan con ella sean compatibles con la implementación elegida. Para ello, el desarrollador solo tiene que crear una clase que derive de la clase jakarta.ws.rs.core.Application. Esta clase se encontrará y utilizará en la fase de configuración de la implementación JAX-RS elegida.

A continuación, se muestra un ejemplo de una clase derivada de la clase jakarta.ws.rs.core.Application:

import javax.ws.rs.ApplicationPath;  
import javax.ws.rs.core.Application;  ...

Exposición de recursos

1. Presentación

Para manipular un recurso, la aplicación cliente necesita conocer su dirección URL. Desde esta URL, la aplicación podrá realizar una petición HTTP con el método de consulta deseado (normalmente, GET, POST, PUT o DELETE). Esta petición desencadenará la llamada al método de recurso de la clase de recurso que el desarrollador escribió para responder a la petición.

De forma predeterminada, se crea una nueva instancia de esta clase para cada petición hacia este recurso. Primero se llama al constructor y, a continuación, se inyectan las dependencias de la petición antes de llamar al método de recurso adecuado.

2. La clase de recurso y sus métodos

La clase de recurso es un POJO (Plain Old Java Object). Esta clase se utiliza para definir un recurso accesible a través de una URL. Como mínimo, esta clase debe tener un método anotado con un indicador de método de petición (@GET, @POST, @PUT, @DELETE@HEAD u @OPTION) presente en el paquete jakarta.ws.rs.

La clase o método también debe estar anotado con @Path para definir la URL contextual. Por lo tanto, la URL de acceso es la concatenación de la URL raíz de la aplicación (definida por @ApplicationPath) y la URL contextual (definida por @Path).

A continuación, se muestra un ejemplo de una clase de recurso básica denominada fr.ediciones_eni.jakartaee.jaxrs.services.GestionDeportes:

import javax.ws.rs.GET;  
import javax.ws.rs.Path;  
  
@Path("/Deportes")  
public class GestionDeportes {  
  
  
    @GET  
    public String getDeportes()  
    {  
        return "Tenis,Squash,Pádel,Bádminton";  
    }  
} 

Esta clase de recurso se utiliza para responder a una petición en la dirección URL /REST/Deportes con el método GET. En el entorno de desarrollo, la dirección URL completa es http://localhost:8080/Proyecto_REST/REST/Deportes.

La ejecución de esta petición en el explorador genera el siguiente resultado:

images/cap6_pag12.png

3. Extraer e inyectar información

Con cada petición, se crea una nueva instancia...

Validar los datos

La validación de datos garantiza que los datos cumplan ciertas restricciones predefinidas. Este es un amplio aspecto abordado a través de la tecnología llamada Bean Validation. Este aspecto ya se ha tratado en el capítulo dedicado a JSF (dentro de la sección Validación con la especificación Bean Validation). En esta sección, se proporciona información general sobre su uso dentro del ámbito de los servicios web REST.

1. Anotaciones

Todos los atributos de las clases de recurso y los parámetros de los métodos de recurso definidos con las anotaciones descritas anteriormente, se pueden enviar para su validación. Para hacer esto, existe un conjunto de anotaciones básicas presentes en el paquete jakarta.validation.constraints.

Estas anotaciones incluyen:

  • @NotNull para definir un elemento obligatorio,

  • @Min para definir el valor entero mínimo de un valor numérico,

  • @Max para establecer el valor entero máximo de un valor numérico,

  • @Size para establecer el tamaño mínimo y máximo de una cadena de caracteres,

  • @Pattern para definir una expresión regular que se debe respetar.

  • También es posible crear su propia restricción. Para hacer esto, se debe crear una anotación asociada a una clase que implemente la interfaz jakarta.validation.ConstraintValidator (esta descripción está fuera del alcance de este libro).

2. Configurar implementaciones JAX-RS...

Proveedores

1. Presentación

La implementación JAX-RS utilizada se puede enriquecer con las clases llamadas provider. Estas clases permiten enriquecer el comportamiento de la implementación para el procesamiento de peticiones.

Estas clases deben implementar una o más interfaces de la especificación JAX-RS y deben estar anotadas con @Provider para ser identificadas automáticamente por parte de la implementación utilizada durante el inicio.

De forma predeterminada, solo se crea una instancia de estas clases por aplicación. Es obligatorio un constructor público y puede contener parámetros anotados con @Context. Por otro lado, no es posible inyectar a través de esta anotación información específica de una petición, ya que de forma predeterminada solo habrá una instancia.

2. Entity providers

Presentación

Las entity providers permiten asociar los tipos Java con sus representaciones en el cuerpo de las peticiones y las respuestas. Las entity providers son los MessageBodyReader y MessageBodyWriter mencionados en las secciones anteriores. Ambos tipos son interfaces genéricas. Para poder utilizarse, se deben implementar usando clases.

Cuando llega una petición al servidor, y antes de que se ejecute el método de recurso, se utiliza un MessageBodyReader para leer el contenido del cuerpo de la petición.

Para devolver una respuesta al usuario, se debe escribir contenido en el cuerpo de la respuesta. Este es el papel de MessageBodyWriter.

Hasta ahora, los ejemplos se han limitado a métodos de recurso que devuelven una cadena de caracteres. La razón es sencilla: las implementaciones JAX-RS deben incluir entity providers para determinados tipos Java (como java.lang.String), para ciertos tipos de medios.

A continuación, se muestra la lista de tipos Java que deben ser compatibles:

  • Para todos los tipos de medios (*/*):

  • byte[]

  • java.lang.String

  • java.io.InputStream

  • java.io.Reader

  • java.io.File

  • javax.activation.DataSource

  • StreamingOutput, solo el MessageBodyWriter.

  • Para el tipo de medio XML (text/xml, application/xml y application/*+xml):

  • javax.xml.transform.Source

  • javax.xml.bind.JAXBElement

  • Para los medios de tipo application/x-www-form-urlencoded:

  • Contenido en forma de MultivaluedMap<String,String>

  • Para medios de tipo text/plain:

  • java.lang.Booleano

  • java.lang.Character

  • java.lang.Number. La conversión...

Filtros e interceptores

Los filtros e interceptores permiten agregar procesamiento a las peticiones. Estos procesamientos pueden ser:

  • Escribir registros de actividad.

  • Gestionar la autenticación.

  • Gestionar la compresión/descompresión del contenido de la petición.

  • Etc.

Los filtros permiten implementar un procesamiento independientemente de la URL solicitada. Los interceptores permiten configurar el procesamiento si se utiliza un MessageBodyReader o un MessageBodyWriter. Consulte la sección La especificación JAX-RS - Funcionamiento general para visualizar la posición de estos pasos en el procesamiento global de una petición.

1. Filtros

Introducción

Los filtros son clases que implementan la interfaz jakarta.ws.rs.contenedor.ContainerRequestFilter o la interfaz jakarta.ws.rs.container.ContainerResponseFilter. La primera interfaz permite configurar un procesamiento antes de la ejecución del método de recurso, mientras que la segunda interfaz se utiliza para implementar un procesamiento después de la ejecución del método de recurso.

A continuación, se muestra el código para estas dos interfaces:

public interface ContainerRequestFilter   
{  
    void filter(ContainerRequestContext requestContext) throws IOException; 
}  
public interface ContainerResponseFilter  
{  
    void filter(ContainerRequestContext requestContext,  
    ContainerResponseContext responseContext) throws IOException;  
} 

Ambos describen un método filter(). Este es el método al que se llamará en la cadena de procesamiento. La firma es diferente, ya que el primero solo recibe un parámetro de tipo ContainerRequestContext, mientras que el segundo recibe un parámetro adicional de tipo ContainerResponseContext.

Estos argumentos permiten que el filtro pueda acceder a la información específica de la petición. Por ejemplo, el filtro puede leer cabeceras de petición (o respuesta) y modificarlas si es necesario. Opcionalmente, el filtro puede poner el procesamiento de la petición en estado de fallo, llamando al método abortWith(Response) presente en el parámetro requestContext. El objeto Response que se pasa como argumento de este método es el objeto a partir del cual se generará...

Complemento de implementación

La búsqueda de clases providers que deben ser soportadas por la implementación elegida para responder a las diferentes peticiones se realiza recorriendo todas las clases accesibles para averiguar si están anotadas con @Provider. Estas clases pueden estar en el directorio WEB-INF/classes del proyecto, pero también en una librería a la que se haga referencia en el directorio WEB-INF/lib o en otro directorio del classpath. Este mecanismo es muy interesante en la fase de desarrollo. En la producción, tiene más sentido establecer un mecanismo más directivo.

Para ello, se puede enriquecer la clase ConfigurationApplicationREST sobrecargando los métodos getClasses() y getSingletons() de la clase madre.

De forma predeterminada, el método getClasses() devuelve una lista vacía que indica a la implementación elegida que busque clases por sí misma. Es posible cambiar el comportamiento de este método para que devuelva de manera explícita las clases que se van a utilizar. En este caso, la implementación elegida solo se basará en esta lista de clases para responder a las peticiones.

En algunos casos, puede ser necesario querer solo una instancia de algunas de estas clases. En este caso, debe sobrecargar el método getSingletons() para que devuelva la instancia de las diferentes clases de las que desea tener solo una instancia....

La API de cliente

1. Introducción

La especificación JAX-RS proporciona una API cliente. Esta API permite a las aplicaciones Java consultar servicios web REST. Los componentes principales de esta API se encuentran en el paquete jakarta.ws.rs.client. Las interfaces y las clases de este paquete definen los mecanismos para crear una petición a un servicio web REST y procesar la respuesta resultante.

2. Funcionamiento general

A continuación, se muestra el esquema que puede encontrar en el apéndice de la especificación oficial:

images/06EP24N.png

Como puede observar, el funcionamiento del lado del cliente es muy similar al del servidor.

Es posible implementar filtros en la petición (antes de enviarla) y en la respuesta (después de recibirla), en las etapas denominadas ClientRequest Chain y ClientResponse Chain. El funcionamiento es idéntico a los mecanismos presentes en el servidor. Solo necesita implementar las interfaces jakarta.ws.rs.client.ClientRequestFilter y jakarta.ws.rs.client.ClientResponseFilter.

Las etapas WriteTo Chain y ReadFrom Chain son idénticas a los procesos descritos en el servidor. Incluso es posible utilizar las mismas clases en el servidor y en el cliente si es necesario.

La etapa HTTP Invocation se utiliza para enviar la petición al servidor, cuyos procesos se materializan mediante la etapa Request/Response.

El último paso, denominado Reponse Processing, se corresponde con la lectura y procesamiento de la respuesta obtenida.

3. La implementación del proyecto y las dependencias

Como parte del libro, la aplicación cliente se desarrollará como una consola Java clásica a partir de un proyecto de Gradle llamado Proyecto_Cliente_REST.

Cuando se crea el proyecto, solo falta modificar el archivo build.gradle para configurar las dependencias necesarias:

 Para...

El lado del cliente en JavaScript

1. Introducción

La noción de servicio web REST a menudo se asocia con la noción de aplicación cliente accesible a través de un navegador web. El lenguaje utilizado para comunicarse directamente con el servicio web es JavaScript, con tecnología AJAX. Hoy en día, este lenguaje es muy popular y permite crear aplicaciones web ricas y adaptadas a las expectativas de los usuarios en términos de funcionalidad y ergonomía. JavaScript se puede usar solo, pero a menudo se utiliza a través de frameworks como Angular, React o Vue.js, por nombrar solo los más populares. Por supuesto, el objetivo de esta sección no es entender este lenguaje y los frameworks, sino que se limitará a presentar el funcionamiento básico para lanzar peticiones a un servicio web REST desde un programa escrito en JavaScript. La API Fetch se utilizará para realizar peticiones AJAX. Está disponible de forma nativa en los navegadores modernos.

2. La implementación del proyecto

Esta sección se basará en un nuevo proyecto llamado Proyecto_WEB_Cliente_REST. Para crearlo, simplemente use el menú File - New - Dynamic Web Project y complete el cuadro de diálogo de la siguiente manera:

images/cap6_pag70.png

También se puede ejecutar usando el servidor Tomcat. Siéntase libre de eliminar los directorios WEB-INF y META-INF generados. No son útiles en este proyecto. Finalmente, agregue un archivo index.html al directorio webapp:

images/cap6_pag72.png

A continuación, se muestra la estructura básica de este archivo:

<!DOCTYPE html>  
<html>  
   <head>  
       <meta charset="UTF-8">  
       <title>Página de demostración de un cliente web REST</title>  
       <script type="text/javascript">  
           //EL CÓDIGO JAVASCRIPT  
       </script>  
   </head>  
   <body>  
       <!—La visualización de la información en HTML -->  
   </body>  
</html> 

La parte <head> contendrá el código JavaScript útil...

Conclusión

Este capítulo proporciona una primera visión general de la implementación de los servicios web REST. Para profundizar en el tema, no dude en consultar la documentación oficial en el sitio web de Jakarta EE (https://jakarta.ee/) y de W3C.