@Controller("/numbers")
public class NumberGeneratorController {
@Inject
NumberGeneratorService service;
@Get("/list{?size}")
Single<int[]> list(Optional<Integer> size){
return service.list( size.orElse(99+1) );
}
}
En esta serie de post acerca de programación reactiva voy a ir contando los pasos que estoy dando para ir practicando con esta forma de programación y más en concreto su uso en aplicaciones HTTP con Micronaut
En el post anterior (reactivex-1.html) vimos mediante un par de ejemplos sencillos cómo un Controller puede ofrecer recursos de forma reactiva en lugar de bloqueante. En este segundo post simplemente vamos a estructurar un poco mejor el código usando un Service y dejar así el Controller más "limpio"
@Controller("/numbers")
public class NumberGeneratorController {
@Inject
NumberGeneratorService service;
@Get("/list{?size}")
Single<int[]> list(Optional<Integer> size){
return service.list( size.orElse(99+1) );
}
}
@Singleton
public class NumberGeneratorService {
Single<int[]> list( Integer size) {
Random rnd = new Random();
return Single.just(
IntStream.
range(1, size).
map(i -> Math.abs(rnd.nextInt())).
toArray()
);
}
}
Como puedes ver, simplemente hemos movido el código al servicio y hacemos que el controlador lo invoque directamente.
Hasta ahora el código era devolver una lista de números que generamos con una línea de código (partida en varias para
mejorar su lectura, pero una línea de código al fín y al cabo). Sin embargo muchas veces la lógica a implementar
requerirá de algo más complejo, por lo que un simple just
no nos servirá. Crearemos entonces un Single que emitirá
el resultado (o fallo) cuando se complete dicha lógica
Recuerda que además de Single, existen otros tipos reactivos interesantes como FLowable o Maybe. Por ahora seguiremos trabajando con Single el cual nos permite notificar un resultado o un error.
Single<int[]> listWithBoundControl( Integer size){
return Single.create( emitter ->{
if( size > 100){
emitter.onError(new ArrayIndexOutOfBoundsException());
return;
}
Random rnd = new Random();
int[] ret = new int[size];
for(int i=0; i<size; i++){
ret[i] = Math.abs(rnd.nextInt());
}
emitter.onSuccess(ret);
});
}
En este ejemplo vemos que podemos notificar un error (si por ejemplo el tamaño que nos piden a generar excede un límite), ejecutar código en una lambda (o llamando a una función privada, etc) y notificar que hemos terminado proporcionando un resultado.
La "magia" en este código es que tanto el controller como el servicio lo que devuelven en las llamadas es un Single
el cual el framework, micronaut en este caso, va a manejar para ejecutarlo y devolver el resultado cuando se ejecute.
La segunda "magia" (que a mí particularmente me fascina) es la capacidad del compilador de comprobar que realmente
estamos devolviendo lo que dice la firma del método que devolvemos. Es decir, si pruebas a cambiar el objeto que
devolvemos en onSuccess
por un String, por ejemplo, el compilador lo detecta y no compila.
En este segundo, y corto, post hemos visto cómo ejecutar una lógica de negocio más compleja y notificar el resultado
mediante el uso de emitter
2019 - 2024 | Mixed with Bootstrap | Baked with JBake v2.6.7