Paso de parámetros con PathParam y QueryParam

Cómo usar PathParam y QueryParam para especificar en la URL ciertas variables y que su contenido esté disponible desde las funciones de nuestros endpoints. De este modo podemos hacer endpoints cuyo comportamiento dependa de la información que le enviemos como parámetro. En este vídeo vemos estas dos formas de enviar información, que será complementado en el futuro con el envío de cargas completas compatibles con otro tipo de verbos HTTP.

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 llamado q cuyo valor es hola. 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=es tenemos dos paráemtros: q con el valor hola y lang con 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.

Lista de reproducción
  1. 1
    Qué es Quarkus y cómo crear un proyecto
    8 minutos
  2. 2
    ¿Cómo crear endpoints en Quarkus?
    7 minutos
  3. 3
    Paso de parámetros con PathParam y QueryParam
    8 minutos
  4. 4
    Retorno de objetos JSON
    7 minutos
  5. 5
    Definir un endpoint POST
    7 minutos
  6. 6
    Servicios e inyección de dependencia
    8 minutos
  7. 7
    Response y ResponseBuilder
    8 minutos
  8. 8
    ExceptionMapper y tratamiento de errores
    9 minutos