En muchas ocasiones querremos que nuestros endpoints puedan recibir información del exterior, como puede ser mediante parámetros o paso de payloads. De este modo, la respuesta de un endpoint y la acción en general que se ejecute a consecuencia de tratar de usar un recurso podrá depender de la propia información que estemos mandando como parámetro.
Existen varias formas de pasar información a un endpoint, y como de momento estamos centrándonos en endpoints que usen el verbo HTTP GET, vamos a ver las primeras dos formas.
QueryParam
Los query params son los parámetros que vienen en una URL después de la interrogación. Por ejemplo, puede que alguna vez hayas visto que una URL lleva un caracter de interrogación y a continuación una secuencia de caracteres separados por iguales y por ampersands. Esos son los query params.
- En la cadena de caracteres
/search?q=hola, estamos llamando a la URL /search, con un queryparam llamadoqcuyo valor eshola. El nombre y el valor de un parámetro se separa por el símbolo igual. - En caso de pasar múltiples parámetros, los podemos separar usando el ampersand. Por ejemplo, en
/search?q=hola&lang=estenemos dos paráemtros:qcon el valor hola ylangcon el valor es.
En el caso de Quarkus, podemos pasar información mediante parámetros a un endpoint usando la anotación @QueryParam, que encontramos en el paquete jakarta.ws.rs. Los parámetros le entran a nuestro endpoint como un argumento de función más, lo que le permite integrarse de forma natural con el lenguaje de programación que estemos usando, como en el siguiente ejemplo.
package quarkus;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/saludar")
public class EcoBasicResource {
@GET
public String saludar(@QueryParam("mensaje") String mensaje) {
return "> " + mensaje;
}
}
Aquí tenemos un método llamado saludar, que tiene un parámetro: mensaje. Este parámetro es de tipo String y como lleva la anotación @QueryParam("mensaje") está conectado con el query param mensaje. Si ahora visitamos la ruta /saludar?mensaje=Hola, se invocará nuestra función saludar(), debido a que la ruta coincide con la que hay declarada en el parámetro Path, y además el valor de la variable mensaje se establecerá a Hola, porque es lo que vale el queryparam correspondiente de acuerdo con lo especificado en la anotación.
Algunos otros ejemplos:
* GET /saludar?mensaje=Buenas => > Buenas
* GET /saludar?mensaje=Hey => > Hey
Si no ponemos un query param, Quarkus nos pasará un valor nulo en el parámetro. En este caso, por ejemplo, si visitamos sin más /saludar, la variable mensaje valdrá null, por lo que la salida será un poco especial:
GET /saludar HTTP/1.1
Host: localhost:8080
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
content-length: 6
> null
Ese null es el propio parámetro valiendo null y siendo serializado a string. Si quisiésemos detectar el caso en el que un query param está vacío, tendríamos que tratarlo. Por ejemplo, mediante un if:
package quarkus;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/saludar")
public class EcoBasicResource {
@GET
public String saludar(@QueryParam("mensaje") String mensaje) {
if (mensaje == null) {
return "No sé muy bien qué decir";
} else {
return "> " + mensaje;
}
}
}
Con esto ahora, si no le pasamos el query param, se detectará que la variable mensaje tiene un avlor nulo y por lo tanto se devolvería el mensaje de fallback No sé muy bien qué decir, en vez de simplemente serializar un valor nulo.
Otras opciones implicarían usar la moderna API de Optional para tratar el caso de una variable nula, algo que nos puede ser de utilidad si vamos a transformar ese valor en otros, como puede ser un dato que pidamos a través de un repositorio o de una base de datos.
package quarkus;
import java.util.Optional;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
@Path("/saludar")
public class EcoBasicResource {
@GET
public String saludar(@QueryParam("mensaje") String mensaje) {
return Optional.ofNullable(mensaje)
.map((msg) -> "> " + msg)
.orElse("No sé muy bien qué decir aquí");
}
}
Path params
Otra manera de codificar parámetros en Quarkus es mediante el uso de parámetros que se codifican en la propia URL. Esto es una característica moderna que puede que haya gente que ya tenga costumbre de usar, puesto que se alinea muy bien con la filosofía REST, tratando los recursos como URLs concretas. Por ejemplo, si tuviésemos una API que codifica una lista de estudiantes, podríamos usar el recurso /estudiantes para obtener un listado completo de los estudiantes, pero podríamos obtener información concreta sobre cada estudiante a través de una URL que codifique como subruta su identificador, como /estudiantes/1234L para el estudiante con ID 1234L, o /estudiantes/2345R para el estudiante con ID 2345R.
En el caso de Quarkus, podemos hacer esto mediante la anotación @PathParam, también del paquete jakarta.ws.rs. A esta anotación le diremos como parámetro el nombre de la variable de ruta que queremos asociar a la variable Java donde se recibirá el valor, como vamos a ver en el siguiente ejemplo. Aprecia que en este caso, el @Path que le damos al endpoint es un poco especial, porque va escrito entre llaves. Cuando pasamos llaves a esta anotación, lo que crea es una URL dinámica. Ese {nombre} no es una constante sino una variable capturada. Esencialmente, permite captura cualquier cosa que pongamos después de /saludar/ será válida y será atendida por ese endpoint, metiendo en el pathparam nombre lo que hayamos puesto:
/saludar/John=> ahora{nombre}vale John./saludar/Ana=> ahora{nombre}vale Ana./saludar/Elena=> ahora{nombre}vale Elena.
Cuando luego usamos la anotación @PathParam, lo que hacemos es pedirle a Quarkus que el parámetro de ruta que se llame como le decimos en el parámetro sea enviado a la variable a la que acompaña la anotación. Así que en cada caso, el valor que pongamos en la ruta se transfiere a la variable.
El ejemplo completo queda del siguiente modo:
package quarkus;
import java.util.Optional;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.QueryParam;
@Path("/saludar")
public class EcoBasicResource {
@GET
@Path("/{nombre}")
public String saludo(@PathParam("nombre") String nombre) {
return "Hola " + nombre;
}
}
Con esto, visitar /saludar/Juan hace que el path param {nombre} valga Juan, y por lo tanto al invocar el método, el String nombre ahora tiene como valor la cadena de caracteres Juan. De modo que evaluando el retorno de este método, tiene sentido que ese endpoint devuelva Hola Juan.
Los path params pueden ser raiz de otros endpoints. Por ejemplo, si usamos /saludar/{nombre}/gritar, lo que ocurrirá ahora es que cualquier petición que cumpla con el patrón saludar + cualquier cosa + gritar, será atendida por el endpoint. En el siguiente ejemplo, hacemos que visitar esta ruta genere un resultado en mayúsculas:
@GET
@Path("/{nombre}/gritar")
public String gritar(@PathParam("nombre") String nombre) {
return "QUÉ ALEGRÍA VERTE " + nombre.toUpperCase();
}
Por lo que si visitamos /saludar/Maria/gritar, se asigna la variable nombre a Maria, pero dado que termina por /gritar entonces será atendido por el endpoint, provocando como respuesta QUE ALEGRÍA VERTE MARIA.