Heroku I: Introducción, creación de un proyecto y despliegue

Inicio la primera entrada, de un conjunto de dos post, cuyo tema principal es Heroku. Definimos Heroku como un servicio en la nube, en concreto,  una plataforma como servicio de diferentes lenguajes, como por ejemplo: Java, Ruby y Node.js. En esta entrada me centraré en la creación de un proyecto Java y en su despliegue.

bombillas

El site de Heroku es el siguiente: https://www.heroku.com. Para la utilización de esta plataforma es necesario la creación de una cuenta para poder desplegar las aplicaciones que desarrollemos; dichas aplicaciones, las podremos gestionar desde el panel de control; así como, la selección de la base de datos de la aplicación.

En esta entrada, voy a realizar la descripción de los pasos para la creación de un proyecto Java así como el despliegue en la plataforma. Para la descarga del cliente y la guía oficial se puede acceder mediante el siguiente enlace: https://devcenter.heroku.com/articles/getting-started-with-java

El repositorio que emplea Heroku es Git. Si el lector desconoce este repositorio, le dejo los enlaces que he realizado sobre Git, estos son:

El proyecto ejemplo, es un proyecto Java con servicios REST sobre Jersey. Los pasos a realizar son los siguientes:

1.- Ejecutaremos el comando maven para la generación de arquetipos, en nuestro caso utilizaremos el arquetipo jersey-heroku-webapp:

mvn archetype:generate -DarchetypeArtifactId=jersey-heroku-webapp -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=com.example -DartifactId=simple-heroku-webapp -Dpackage=com.example -DarchetypeVersion=2.8

El resultado de la ejecución del comando es la creación de las carpetas del proyecto así como la creación de los ficheros: Procfile y system.properties. Estos ficheros contienen información de configuración y se localizan en la carpeta raíz del proyecto.

2.- Desde la línea de comandos, realizaremos el logueo el Heroku tecleando el comando heroku login.

3.- Realizaremos la creación del repositorio Git en el proyecto creado; para ello, teclearemos el comando: git init

4.- Creación de la aplicación en la plataforma Heroku mediante el comando: heroku create. El resultado del comando: creación del proyecto en la plataforma y, en la línea de comandos, se muestra los enlaces de la url de la aplicación y el enlace al proyecto git.

5.- Realizaremos la codificación del proyecto.

6.- Cambiaremos el estado de los elementos a subir al repositorio de git; entre otros, se debe de  subir: el fichero pom.xml, Procfile, el fichero system.properties y la carpeta src. Un ejemplo es el siguiente: git add src/ Procfile system.properties

7.- Realizaremos el commit al repositorio mediante el  comando commit, por ejemplo,  el commit inicial sería de la siguiente forma:  git commit -a -m «Commit inicial» . El comando anterior corresponde con el primero de todos. Si no se ha subido todo el código, o bien, no se ha terminado de codificar, repetimos los pasos desde el punto 5.

8.- Una vez que tenemos en nuestro repositorio todo el aplicativo, realizaremos el despliegue en la plataforma. Para ello, ejecutamos el siguiente comando: git push heroku master. En este punto, es posible que tengamos problemas con las claves SSH en la conexión a Heroku. Para solventarlas, deberemos de crear una clave nueva mediante el comando ssh-keygen -y rsa; una vez creada, realizaremos la subida de la clave a Heroku mediante el comando heroku keys:add; para ver las claves subidas, ejecutamos el comando heroku keys. Si se desea profundizar en el tema, el enlace de la documentación es el siguiente.

9.- Para la realización de las pruebas, se accede a la url obtenido del punto 4 con los servicios; por ejemplo: http://damp-castle-9224.herokuapp.com/myresource

En la siguiente entrada, Heroku II; Heroku con Eclipse, realizaré la descripción de la creación de los pasos descritos en esta entrada pero desde Eclipse.

 

Servicios REST con Jersey. Peticiones Asíncronas

En la entrada anterior, Servicios REST con Jersey, realicé una descripción de la definición de servicios REST con Jersey, definición de clientes y cómo probar los servicios con SOAP UI. En esta entrada, Servicios REST con Jersey. Peticiones Asíncronas, me centraré en la definición de servicios asíncronos, así como, los clientes de dichos servicios.

La creación del proyecto y su configuración es exactamente igual que la entrada anterior.

Los servicios que podemos realizar son de tres tipos: un servicio asíncrono básico, un servicio asíncrono con Timeout el cual se puede implementar de dos formas y, por último, un servicio chunked, es decir, un servicio que implica una lectura, un procesamiento y una escritura. En los siguientes apartados realizaremos la definición práctica de un servicio y un cliente por cada tipo.

En las diferentes formas de definir un servicio asíncrono que voy a presentar en los siguientes apartados, la firma de método, es siempre la misma. En todas las formas, se pasa un elemento de la clase AsyncResponse con la anotación @Suspended. Esta anotación, determina qué método es asíncrono y permite inyectar la respuesta del resultado del servicio.

Tarea asíncrona básica

La tarea asíncrona define un servicio que realiza una operación pesada y, cuando finaliza, retorna la respuesta. En nuestro caso, para las pruebas, la operación pesada consiste en esperar 10 segundos. El servicio responde con un literal con el texto “10 segundos”. El cliente realiza una petición asíncrona con un objeto de la clase AsyncInvoker.

El snippet del servicio con la tarea asíncrona básica es la siguiente:

 @GET
 @Path("/ejem1")
 @Produces(MediaType.TEXT_PLAIN)
 public void asyncGet(@Suspended final AsyncResponse asyncResponse) {
   new Thread(new Runnable() {
       @Override
       public void run() {
         String result = operacionPesada();
         asyncResponse.resume(result);
       }
       private String operacionPesada() {
         try {
           Thread.sleep(10000);
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
         return "10 segundos";
       }
   }).start();
 }

El snippet del cliente con la tarea asíncrona es el siguiente:

 private void tareaAsincronaBasicaForma1() {
   Client client = ClientBuilder.newClient();
   AsyncInvoker async = client.target(HTTP_LOCALHOST_8080_WEBAPI + "/asincronos/ejem1").request().async();
   Future<Response> future = async.get();
   Response response = null;
   try {
     response = future.get();
   } catch (InterruptedException e) {
      e.printStackTrace();
   } catch (ExecutionException e) {
      e.printStackTrace();
   }
   System.out.println("Hemos obtenido respuesta estado->" + response.getStatus());
   System.out.println("Hemos obtenido respuesta respuesta->" + response.readEntity(String.class));
 }

Tarea asíncrona con timeout

El servicio asíncrono con TimeOut tiene la misma estructura que la básica salvo que se define un manejador de TimeOut. Este manejador se define en la respuesta asíncrona que se define como parámetro del servicio. El nombre del manejador es TimeoutHandler el cual define un método handlerTimeout. Una vez que se define el manejador y se define el tiempo, en nuestro caso en segundos, se define la tarea y se inicia el hilo. De la misma forma que el caso anterior, se define un método cuya funcionalidad tiene un coste alto en tiempo de ejecución. El código del cliente no tiene cambios significativos.

El snippet del servicio con la tarea asíncrona con timeout es el siguiente:

 @GET
 @Path("/ejem2")
 @Produces(MediaType.TEXT_PLAIN)
 public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) {
    asyncResponse.setTimeoutHandler(new TimeoutHandler() {
      @Override
      public void handleTimeout(AsyncResponse asyncResponse) {
       asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE).entity("Excedió el tiempo de ejecución.")
      .build());
    }});
    asyncResponse.setTimeout(20, TimeUnit.SECONDS);
      new Thread(new Runnable() {
          @Override
          public void run() {
             String result = operacionPesada();
             asyncResponse.resume(result);
          }
          private String operacionPesada() {
            try {
              Thread.sleep(21000);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
            return "10 segundos";
         }
     }).start();
 }

El snippet del cliente con la tarea asíncrona con timeout es el siguiente:

private void tareaAsincronaTimeOutForma1() {
 Client client = ClientBuilder.newClient();
 AsyncInvoker async = client.target(HTTP_LOCALHOST_8080_WEBAPI + "/asincronos/ejem2").request().async();
 Future<Response> future = async.get();
 Response response = null;
 try {
    response = future.get();
 } catch (InterruptedException e) {
    e.printStackTrace();
 } catch (ExecutionException e) {
    e.printStackTrace();
 }
 System.out.println("Hemos obtenido respuesta estado->" + response.getStatus());
 System.out.println("Hemos obtenido respuesta respuesta->" + response.readEntity(String.class));
}

Tarea asíncrona con timeout e implementando CompletionCallback

La implementación del interfaz CompletionCallback permite definir un manejador; cuando la tarea termina, se envía una respuesta al cliente; el cliente, define un componente que implementa el interfaz InvocationCallback el cual le permite controlar cuando se ha completado la operación, o bien, cuando se ha producido una excepción.

El snippet del servicio con la tarea asíncrona con timeout y CompletionCallback es el siguiente:

 @GET
 @Path("/ejem3")
 @Produces(MediaType.TEXT_PLAIN)
 public void asyncGetWithTimeoutAndCompletionCallback(@Suspended final AsyncResponse asyncResponse) {
   asyncResponse.register(new CompletionCallback() {
     @Override
     public void onComplete(Throwable throwable) {
        if (throwable == null) {
          numberOfSuccessResponses++;
        } else {
         numberOfFailures++;
         lastException = throwable;
        }
     }
 });
 new Thread(new Runnable() {
   @Override
   public void run() {
     String result;
     result = operacionPesada();
     asyncResponse.resume(result);
   }
   private String operacionPesada() {
      try {
        Thread.sleep(5000);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      return "5 segundos en ejecución.";
    }
   }).start();
 }

El snippet del cliente con la tarea asíncrona con timeout y CompletionCallback es el siguiente:

private void tareaAsincronaCompletionCallback() {
 Client client = ClientBuilder.newClient();
 AsyncInvoker async = client.target(HTTP_LOCALHOST_8080_WEBAPI + "/asincronos/ejem3").request().async();
 Future<Response> future = async.get(new InvocationCallback<Response>() {
   @Override
   public void completed(Response response) {
      System.out.println("Estado respuesta=" + response.getStatus());
      System.out.println("Respuesta=" + response.readEntity(String.class));
   }
   @Override
   public void failed(Throwable throwable) {
      throwable.printStackTrace();
   }
  });
}

Tarea asíncrona con chunked

El servicio chunked es aquel servicio cuya tarea realiza una operación de lectura, un procesamiento y “una escritura”. La salida del servicio difiere del resto ya que retorna un objeto de la clase ChunkedOutput.

El snippet del servicio con la tarea asíncrona con chunked es el siguiente:

 @GET
 @Path("/ejem4")
 @Produces(MediaType.TEXT_PLAIN)
 public ChunkedOutput<String> getChunkedResponse() {
    final ChunkedOutput<String> output = new ChunkedOutput<String>(String.class);
    new Thread() {
       public void run() {
         try {
           String chunk;
           while ((chunk = proximoString()) != null) {
             output.write(chunk);
           }
         } catch (IOException e) {
             e.printStackTrace();
        } finally {
          try {
             output.close();
          } catch (IOException e) {
             e.printStackTrace();
          }
       }
     }}.start();
    return output;
 }
 private String proximoString() {
    String resultado = "";
    try {
      new Thread().sleep(2000);
      resultado = " String_" + new Random().nextInt();
      if(this.numeroDeChunk == 3){
        resultado = null;
      }
      this.numeroDeChunk++;
    } catch (InterruptedException e) {
       e.printStackTrace();
    }
    return resultado;
 }

El snippet del cliente con la tarea asíncrona con chunked es el siguiente:

private void tareaAsincronaChunked() {
  System.out.println("\nIniciamos el cliente tareaAsincronaChunked");
  Client client = ClientBuilder.newClient();
  final Response response = client.target(HTTP_LOCALHOST_8080_WEBAPI + "/asincronos/ejem4").request().get();
  final ChunkedInput<String> chunkedInput = response.readEntity( new GenericType<ChunkedInput<String>>(){} );
  String chunk = "";
  while( ( chunk=chunkedInput.read() ) != null ){
     System.out.println("Chunk recibido="+chunk);
  }
  System.out.println("Finalizamos tareaAsincronaChunked...");
}

Si se desea el código ejemplo se puede acceder aquí.

Para mayor comprensión del ejercicio, he dejado en el código las trazas de la consola.

Servicios REST con Jersey

En publicaciones pasadas, he escrito sobre WebServices en diferentes tecnologías. De la misma manera, he realizado lo mismo para definir clientes que consumen dichos servicios. Con esta nueva publicación, añado una nueva tecnología para la definición de WebServices en Java con Jersey.

Las publicaciones pasadas de WebServices son las siguientes:

En la presente entrada, me centraré en cómo definir servicios sencillos con Jersey, clientes que consumen los servicios y la creación de un proyecto de tester con SOAP UI.

Creación del proyecto

La generación de un proyecto para trabajar con Jersey es muy sencillo con Maven; simplemente, tenemos que utilizar los arquetipos predefinidos para Jersey. Los principales arquetipos  son dos: proyecto básico, cuyo identificador es jersey-quickstart-grizzly2; y, para un proyecto web, el identificador del arquetipo es jersey-quickstart-webapp.

La generación del arquetipo para la generación de un proyecto Maven con la configuración básica con Jersey es el siguiente:

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false -DgroupId=mi.paquete -DartifactId=simple-service -Dpackage=mi.paquete -DarchetypeVersion=2.6

La generación del arquetipo para la generación de un proyecto Maven con la configuración para un proyecto web con Jersey es el siguiente:

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-webapp  -DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false  -DgroupId=mi.paquete -DartifactId=simple-service-webapp -Dpackage=mi.paquete  -DarchetypeVersion=2.6

Configuración Maven de Jersey

En esta entrada, me centraré en un proyecto web que soporte Servlet 3.X, y, como servidor embebido, utilizaré Jetty. Así, los elementos importantes del fichero pom son los siguientes:

[...]
<plugin>
 <groupId>org.eclipse.jetty</groupId>
 <artifactId>jetty-maven-plugin</artifactId>
 <version>${jetty.version}</version>
</plugin>
[...]
<dependencyManagement>
 <dependencies>
 <dependency>
 <groupId>org.glassfish.jersey</groupId>
 <artifactId>jersey-bom</artifactId>
 <version>${jersey.version}</version>
 <type>pom</type>
 <scope>import</scope>
 </dependency>
 <dependency>
 <groupId>org.glassfish.jersey.media</groupId>
 <artifactId>jersey-media-json-jettison</artifactId>
 <version>${jetty.version}</version>
 </dependency>
 </dependencies>
</dependencyManagement>
<dependencies>
 <dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet</artifactId>
 </dependency>
 <dependency>
 <groupId>org.glassfish.jersey.media</groupId>
 <artifactId>jersey-media-moxy</artifactId>
 </dependency>
</dependencies>
[...]

Configuración del servidor, fichero web.xml

Para trabajar con Jersey, es necesario definir el Servlet de Jersey para interpretar las peticiones REST. La definición del servlet contiene  lo siguiente: definición del ServletContainer, definición de los parámetros del servlet y el mapeo del Servlet. El snippet con el código es el siguiente:

<servlet>
 <servlet-name>Jersey Web Application</servlet-name>
 <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
 <init-param>
 <param-name>jersey.config.server.provider.packages</param-name>
 <param-value>es.directoandroid</param-value>
 </init-param>
 <init-param>
 <param-name>jersey.config.server.wadl.disableWadl</param-name>
 <param-value>false</param-value>
 </init-param> 
 <init-param>
 <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
 <param-value>true</param-value>
 </init-param>
 <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
 <servlet-name>Jersey Web Application</servlet-name>
 <url-pattern>/webapi/*</url-pattern>
</servlet-mapping>

Un aspecto a destacar es la definición del parámetro jersey.config.server.wadl.disableWadl para permitir la obtención del fichero wadl con la definición de los servicios.

Servicios

Una vez llegado a este punto, solo nos falta la definición de los servicios. Este proceso es sencillo, simplemente, se define una clase con las anotaciones de Jersey. En el ejemplo, defino dos clases: la primera, ServicioEjemploBasico, define unos servicios básicos; y, ServicioEjemploCabeceras, define unos servicios para la utilización de cabeceras y parámetros. Dichas clases tiene la anotación @Path para definir el path de primer nivel de acceso a los servicios; el de segundo nivel, se encuentra en cada método que define cada servicio.

Servicio con JSON

La definición del servicio que sirva una estructura JSON consiste en lo siguiente: utilización de la anotación @Get para definir que es una petición HTTP GET; utilización de la anotación @Produces para definir el tipo de respuesta, en nuestro caso, MediaType.APPLICATION_JSON; y, por último, la utilización de la anotación @Path para definir el path de segundo nivel.

En nuestro ejemplo, el método del servicio retorna un String con una estructura JSON. El snippet del código es el siguiente:

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/ejem1")
public String echoHolaMundo(){
 return "{'mensaje':'Hola Mundo desde Jersey!!!'}";
}

Servicio con XML

La definición del servicio que sirva una estructura XML consiste en lo siguiente: utilización de la anotación @Get para definir que es una petición HTTP GET; utilización de la anotación @Produces para definir el tipo de respuesta, en nuestro caso, MediaType.APPLICATION_XML; y, por último, la utilización de la anotación @Path para definir el path de segundo nivel.

En nuestro ejemplo, el método del servicio retorna un String con una estructura XML. El snippet del código es el siguiente:

@GET
@Produces(MediaType.APPLICATION_XML)
@Path("/ejem2")
public String echoHolaMundoXml(){
 return "<nodo><mensaje>Hola Mundo desde Jersey!!!</mensaje></nodo>";
}

Servicio Json con Bean

La definición del servicio que sirva una estructura JSON utilizando un bean  consiste en lo siguiente: utilización de la anotación @Get para definir que es una petición HTTP GET; utilización de la anotación @Produces para definir el tipo de respuesta, en nuestro caso, MediaType.APPLICATION_XML; y, por último, la utilización de la anotación @Path para definir el path de segundo nivel.

En nuestro ejemplo, el método del servicio retorna un bean con nombre MyBean con los datos de la estructura JSON. El snippet del código es el siguiente:

@GET
@Path("/ejem4")
@Produces(MediaType.APPLICATION_JSON)
public MyBean getJson() {
 return new MyBean("Manolito", 69); 
}

Servicio texto

La definición del servicio que sirva una estructura de texto consiste en lo siguiente: utilización de la anotación @Get para definir que es una petición HTTP GET; utilización de la anotación @Produces para definir el tipo de respuesta, en nuestro caso, MediaType.TEXT_PLAIN; y, por último, la utilización de la anotación @Path para definir el path de segundo nivel.

En nuestro ejemplo, el método del servicio retorna un String. El snippet del código es el siguiente:

@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/ejem3")
public String echo(){
 return "Haciendo echo...";
}

Servicio con parámetro

La definición del servicio al cual se le pasa un parámetro y, para el ejemplo, que sirva una estructura de texto consiste en lo siguiente: utilización de la anotación @Get para definir que es una petición HTTP GET; utilización de la anotación @Produces para definir el tipo de respuesta, en nuestro caso, MediaType.TEXT_PLAIN; la utilización de la anotación @Path para definir el path de segundo nivel; y, para definir el parámetro, se utiliza la anotación @QueryParam con el identificador del parámetro que se pasa desde el cliente.

En nuestro ejemplo, el método del servicio que retorna un String y se le pasa por parámetro queda representado por el snippet siguiente:

@GET
@Path("/ejem2")
@Produces(MediaType.TEXT_PLAIN)
public String get(@QueryParam("parametro") String param) {
 return "parametro pasado=" + param;
}

Servicio con parámetro, valor por defecto y cabecera

En este apartado realizaremos la misma operación que en el anterior; la diferencia, radica en la forma en la cual se asigna el parámetro. En este caso, la asignación del parámetro se realizará por inyección, además, se realizará, de la misma forma, la inyección de un parámetro de la cabecera.

La inyección se realiza sobre atributos de la clase con las siguientes anotaciones: @QueryParam, para el parámetro; @HeaderParam, para el parámetro de la cabecera; y, @DefaultValue, para la asignación del valor por defecto del parámetro en caso de que no exista en la petición. El snippet del ejemplo es el siguiente:

@Path("/header")
public class ServicioEjemploCabeceras {

 @DefaultValue("pordefecto")
 @QueryParam("param1")
 private String param1;
@HeaderParam("header")
 private String header;

El método del servicio queda de la siguiente forma:

@GET
@Path("/ejem1")
@Produces(MediaType.TEXT_PLAIN)
public String get() {
 return "parametro="+param1+" - [header="+header+"]";
}

Cliente

Los clientes son todas aquellas entidades que realizan peticiones a los servicios. Los clientes que definiremos son los clientes que conectan con los servicios definidos anteriormente. La definición de los clientes tiene prácticamente la misma secuencia: primero, creación del cliente; segundo, definición del path del servicio; tercero, definición de la respuesta (JSON, XML, …); cuarto, definición de los parámetro o cabeceras si procede; y, por último, obtención de la respuesta.

Cliente con JSON

El snippet con la definición del cliente a un servicio JSON es el siguiente:

private void servicioJson() {
 System.out.println("\n-*-*- Cliente a servicio con respuesta JSON -*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/servicio1/ejem1");
 Builder request = jsonWebTarget.request(MediaType.APPLICATION_JSON);
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Cliente con XML

El snippet con la definición del cliente a un servicio XML es el siguiente:

private void servicioXml() {
 System.out.println("\n-*-*- Cliente a servicio con respuesta XML -*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/servicio1/ejem2");
 Builder request = jsonWebTarget.request(MediaType.APPLICATION_XML);
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Cliente Json con Bean

El snippet con la definición del cliente a un servicio JSON con bean es el siguiente:

private void servicioJsonConBean() {
 System.out.println("\n-*-*- Cliente a servicio con respuesta JSON -*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/servicio1/ejem4");
 Builder request = jsonWebTarget.request(MediaType.APPLICATION_JSON);
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Cliente texto

El snippet con la definición del cliente a un servicio de texto es el siguiente:

private void servicioText() {
 System.out.println("\n-*-*- Cliente a servicio con respuesta Text -*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/servicio1/ejem3");
 Builder request = jsonWebTarget.request(MediaType.TEXT_PLAIN);
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Cliente con parámetro

El snippet con la definición del cliente a un servicio de texto definiendo un parámetro  es el siguiente:

private void servicioConParametro() {
 System.out.println("\n-*-*- Cliente a servicio con parametros y campos de cabecera-*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/header/ejem2");
 WebTarget queryParam = jsonWebTarget.queryParam("parametro", 123456789);
 Builder request = queryParam.request(MediaType.TEXT_PLAIN);
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Cliente con parámetro y cabecera

El snippet con la definición del cliente a un servicio de texto con un parámetro y una cabecera es el siguiente:

private void servicioConParametrosYCabecera() {
 System.out.println("\n-*-*- Cliente a servicio con parametros y campos de cabecera-*-*-");
 Client client = ClientBuilder.newClient();
 WebTarget webTarget = client.target(HTTP_LOCALHOST_8080_WEBAPI);
 WebTarget jsonWebTarget = webTarget.path("/header/ejem1");
 WebTarget queryParam = jsonWebTarget.queryParam("param1", 1);
 Builder request = queryParam.request(MediaType.TEXT_PLAIN);
 request.header("header", "ValorCabecera");
 Response response = request.get();
 System.out.println("status=" + response.getStatus());
 System.out.println("readEntity=" + response.readEntity(String.class));
}

Pruebas con SOAP UI

Para la realización de las pruebas de los servicios podemos utilizar la herramienta SOAP UI. Al ser un servicio REST, primeramente, debemos de obtener el WADL (Web Application Description Language); para ello, en un navegador escribiremos lo siguiente: http://localhost:8080/webapi/application.wadl ; la respuesta, será una estructura xml con la definición de los servicios.

Una vez arrancado SOAP UI, crearemos un proyecto REST al que le referenciaremos la URL con el contenido del wadl; automáticamente, se creará un proyecto con los clientes y las peticiones para probar cada servicio.

Si se desea el código ejemplo se puede acceder aquí.

En la siguiente entrada, Servicios REST con Jersey. Peticiones asíncronos, realizaré la definición de servicios asíncronos, así como, la definición de sus clientes.