Primeros pasos en programación reactiva, II

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()
        );
    }
}
NOTE

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

WARNING

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.

Resumen

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

Follow comments at Telegram group Or subscribe to the Channel Telegram channel

2019 - 2021 | Mixed with Bootstrap | Baked with JBake v2.6.5