Es habitual que algunos de los parámetros de nuestros servicios sean opcionales para el cliente, lo que provocaría la llega de estos valores en null para nuestra API, lo que puede resultar un problema para algunos parámetros que son requeridos para el correcto funcionamiento del API y que al menos debemos de tener un valor por defecto en caso de no enviarse.
NOTA: Este artículo es parte de un tutorial completo para crear API REST con JAX-RS, si quieres ver el índice completo entra aquí.
Mediante la anotación @DefaultValue
podemos establecer un valor por default a algunos de nuestros parámetros que son opcionales para el cliente, lo que evita que tengan un valor nulo al llegar al API. Esta característica es especialmente buena en casos en los que el API necesita que estos parámetros tengan algún valor a pesar que el cliente no lo envíe, pues dejarlos en null puede provocar el fallo del servicio.
Imaginemos el siguiente ejemplo, tenemos que construir un servicios de consulta de clientes que permita paginar los resultados, por lo que el servicio deberá proporcionar la página actual y el número de registros esperados por página. En este ejemplo, podríamos imagina que si los valores no se definen, entonces el API debería de retornar todo, pero esto puede provocar un problema de performance, por que hay muchísimos clientes y cada cliente tiene una serie de objetos asociados que deberán ser retornados también, provocando una gran carga sobre la base de datos, es por ello, que debemos asegurarnos de que si el API no recibe estos parámetros entonces deberemos establecer un valor por default. Veamos el siguiente ejemplo:
package api.services;
import java.util.*;
import javax.ws.rs.core.*;
@Path("customers")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class CustomersService {
@GET
public Response getCustomers(
@DefaultValue("1") @QueryParam("currentPage") int currentPage,
@DefaultValue("10") @QueryParam("pageSize") int pageSize) {
//Validate input
if(currentPage < 1 || pageSize < 1) {
return Response.ok("Invalid params").build();
}
//ccreate Dataset
List<String> customers = new ArrayList<>();
for(int c = 1 ; c<=100 ; c++) {
customers.add("Customer " + c);
}
//Calculate sublist range
int startIndex = (currentPage-1) * pageSize;
int endIndex = startIndex + pageSize;
//No more results
if(startIndex >=customers.size()) {
return Response.ok(new Object[0]).build();
}
//Prevent ArrayIndexOutOfBoundsException
if(endIndex > customers.size()) {
endIndex = customers.size();
}
//Getting sublist of elements
List<String> filters = customers.subList(startIndex, endIndex);
return Response.ok(filters)
.header("x-size", customers.size())
.header("x-startIndex", startIndex)
.header("x-endIndex", endIndex)
.build();
}
}
Para este ejemplo hemos definido que si el cliente no envía la página actual (currentPage
) le daremos el valor de 1 por default, y para el tamaño de la página (pageSize
) hemos definido el valor de 10. Esto quiere decir que en caso de que el cliente no envíe estos parámetros, regresaremos los 10 primeros registros.
También hemos retornado los headers x-size
, x-startIndex
, x-endIndex
como metadato para el cliente, para que sepa el total de los elementos, el index del primer registro y el último respectivamente.
Veamos algunos ejemplos. En primer lugar probaremos ejecutar el servicio sin ninguno de los parámetros, para comprobar los valores por default:
Podemos comprobar que se han retornado los primeros 10 resultados.
Hora probaremos únicamente con el parámetro pageSize=3, lo que establecerá la página por default en 1, regresando los primeros 3 resultados:
Conclusiones
Los valores por default son una excelente opción para lidiar con valores requeridos por el API, pero que nos obligatorios para el cliente, sin embargo, el echo de que tengamos valores por default, no significa que no debemos validar los parámetros, pues el cliente siempre podrá enviar valores no esperados por el API que provoquen una falla o en el peor de los casos, hacer una inyección SQL.
no sigues agregando mas tutoriales ?
Hola Cris, de vez en cuando agrego, pero no tengo calendario de lanzamientos
¡Hola Oscar!
Lo primero de todo, te doy infinitas gracias por escribir estos tutoriales que me han ayudado un montón, tanto por su simpleza como por sus ejemplos y la disponibilidad del código
Hace mucho que no desarrollo una aplicación web y ahora me han pedido hacer una con REST. He seguido tus tutoriales y ya domino como enviar, recibir y procesar datos. Sin embargo hay algo que no sé, ¿cómo puedo enviar o mostrar estos datos desde/en un html o xhtml? ¿Donde debe estar la página alojada y como la comunico con la clase java destinada a procesar las peticiones http? ¿Hay algo que se me está escapando?
De nuevo muchas gracias y siento cualquier molestia ocasionada
Hola Pablo, eso que comentas ya corresponde a la parte web y no tanto al API REST. Ahora bien, el API REST no va a regresar los datos en HTML, por que no es su objetivo, más bien, lo normal es que lo regresa en JSON y desde el navegador se obtenga ese JSON para mostrar los datos en pantalla.
Para enviar o consumir un API existe una API estándar del navegador llamada FETCH, puedes investigar un poco sobre esta API en Internet, es realmente simple de utilizar.
Saludos.
Hola Oscar,
Piensa continuar con el curso ???
Hola Julian, de momento lo tengo detenido por falta de tiempo, si te interesa profundizar en el tema, te invito a mi curso de Mastering JPA con Hibernate, allí explico todos estos temas con lujo de detalle.
Hola Oscar, primero que nada, te agradezco mucho por tus artículos, están muy bien explicados y me ayudan mucho.
Acabé los artículos relacionados a esté tutorial API REST con Java (JAX-RS), siendo este el último artículo que publicaste, una duda, ¿Ya no piensas seguir actualizando esté tutorial?, ya que veo que en el índice aún hay títulos que no subes.
Veo que recomiendas el curso Mastering JPA con Hibernate, en el cual estoy bastante interesado, ya que como explicas los artículos de este tutorial, creo que me será de bastante ayuda; vi que en el Temario utilizas Payara Server como servidor de aplicaciones, en mi caso, yo estoy utilizando WildFly, sin embargo, espero no sea tan distinto uno del otro en sus conceptos y poder trasladar lo que hagas en Payara a WildFly.
Nuevamente, te agradezco mucho que compartas tus conocimientos con la comunidad, continuaré con el tutorial Java Persistence API (JPA).
Saludos.
Hola Salvador, pues es algo que he quiero terminar, pero mi carga de trabajo me lo ha impedido, es por eso que creé el curso, para que sea mucho más ilustrativo.
Respecto a lo de payara, pues en realidad son los mismos conceptos, los ejemplos funcionan igual ya sea en payara o en Wildfly.