The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Continuum

Durante años, la arquitectura cliente-servidor ha sido el estándar de facto para construir aplicaciones. Pero se ha producido un cambio significativo. La era de un modelo los gobierna a todos ha terminado. Ha surgido una nueva gama de aplicaciones y estilos arquitectónicos que han transformado la forma de escribir el código y de desplegar y ejecutar las aplicaciones. Los microservicios HTTP, las aplicaciones reactivas, la arquitectura basada en eventos y la ausencia de servidor son ahora protagonistas de los sistemas modernos.

Quarkus ha sido diseñado con este nuevo mundo en mente y proporciona soporte de primera clase para estos diferentes paradigmas. Esto no significa que no puedas construir monolitos con Quarkus; puedes hacerlo sin problemas. Al contrario, significa que el modelo de desarrollo de Quarkus se transforma para adaptarse al tipo de aplicación que estés desarrollando, monolito, microservicio, reactivo, dirigido por eventos, funciones...

Microservicios HTTP

Empecemos por lo básico: los microservicios HTTP. En este contexto, necesitas desarrollar un endpoint HTTP, a menudo llamado REST o CRUD. Procesas las peticiones HTTP entrantes, y para ello normalmente necesitas apoyarte en otros servicios, como bases de datos, o en otro servicio HTTP.

Para este tipo de aplicaciones, Quarkus se apoya en estándares conocidos como JAX-RS, JPA y MicroProfile Rest Client, pero también en Hibernate con Panache para simplificar las interacciones con las bases de datos.

Tomemos una aplicación muy sencilla que maneje elementos de la tabla periódica. El código sería algo así:

@Path("/elements")
        public class ElementResource {

    @GET
    public List<Element> getAll() {
        return Element.listAll();
    }

    @GET
    @Path("/{position}")
    public Element getOne(@PathParam("position") int position) {
        Element element = Element.find("position", position).firstResult();
        if (element == null) {
            throw new WebApplicationException("Element with position " + position + " does not exist.", 404);
        }
        return element;
    }

    @POST
    @Transactional
    public Response create(Element element) {
        element.persist();
        return Response.ok(element).status(201).build();
    }

    //...
}

Si eres un usuario de Java EE o Spring, este modelo de desarrollo debería resultarte familiar. Se expone un recurso que contiene métodos anotados con @GET, @POST…​​ ... para manejar las diferentes peticiones. La ruta se especifica utilizando la anotación @Path. Quarkus también soporta anotaciones del Controlador de Spring como @GetMapping or @RestController.

Se puede utilizar el gestor de entidades JPA directamente. Panache propone una alternativa eliminando el boilerplate y exponiendo un registro activo y modelos de repositorio.

Con Panache, la clase Element sería tan simple como:

@Entity
public class Element extends PanacheEntity {

    public String name;
    public String symbol;
    @Column(unique = true)
    public int position;
}

Los microservicios suelen venir en sistemas. Imaginemos ahora que necesitas acceder a otro endpoint HTTP. Puedes usar un cliente HTTP directamente; esto no es más que repetir código boilerplate. Quarkus proporciona una manera de llamar a los endpoints HTTP fácilmente utilizando la API del cliente REST de MicroProfile.

Primero declare su servicio como sigue:

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Element getElement(@PathParam("position") int position);
}

Para cada llamada que pretendas hacer, añade un método y utiliza anotaciones para describir el comportamiento. Puedes combinar el cliente REST con la extensión tolerancia a fallos para manejar los fallos con elegancia. Luego, en tu recurso, sólo tienes que utilizar la interfaz ElementService:

@Path("/elem")
public class ElementResource {

    @RestClient
    ElementService elements;

    @GET
    @Path("/{position}")
    public Element name(@PathParam("position") int position) {
        return elements.getElement(position);
    }
}

Pero puede que te preguntes dónde está configurada la URL, ya que no está en el código. Recuerde que no debe estar codificado porque la URL probablemente depende del entorno. La URL se configura en la configuración de la aplicación:

element-service/mp-rest/url=http://localhost:9001

Ahora se puede actualizar la URL durante el despliegue o en el momento del lanzamiento utilizando las propiedades del sistema o las variables de entorno.

Quarkus no se limita a HTTP. Puede utilizar gRPC o GraphQL, dos alternativas destacadas en el espacio de los microservicios.

Ser reactivo

Los requisitos de las aplicaciones han cambiado drásticamente en los últimos años. Para que cualquier aplicación tenga éxito en la era de la computación en la nube, el Big Data o el IoT, ser reactivo se está convirtiendo cada vez más en el estilo de arquitectura a seguir.

Los usuarios de hoy en día prefieren aplicaciones con un tiempo de respuesta de milisegundos, un tiempo de actividad del 100%, menor latencia, datos push en lugar de pull, mayor rendimiento y elasticidad. Sin embargo, estas características son casi imposibles de conseguir con la arquitectura de software de ayer sin una inversión considerable en recursos, infraestructura y herramientas. El mundo ha cambiado, y tener docenas de servidores, largos tiempos de respuesta (> 500 ms), tiempos de inactividad por mantenimiento o cascadas de fallos no satisface la experiencia de usuario esperada.

Quarkus te ayuda en tu viaje hacia lo reactivo. Quarkus se basa en un núcleo reactivoque permite a tu aplicación mezclar componentes reactivos e imperativos. Como ejemplo, puedes implementar un endpoint HTTP reactivo usando la extensión RESTEasy Reactive como sigue:

@GET
@Path("/elements/{position}")
public Uni<Element> getElement(@PathParam("position") int position) {
    return elements.getElement(position)
        .onFailure().recoverWithItem(FALLBACK);
}

Gracias a la API Reactiva de Mutiny , puedes componer operaciones asíncronas y completar el resultado cuando todo esté hecho sin bloquear los hilos de E/S. Esto mejora mucho el consumo de recursos y la elasticidad. La mayoría de las APIs de Quarkus están disponibles tanto en imperativo como en reactivo. Como ejemplo, puede utilizar la versión reactiva del Cliente REST:

@Path("/elements")
@RegisterRestClient(configKey="element-service")
public interface ElementService {

    @GET
    @Path("/{position}")
    Uni<Element> getElement(@PathParam("position") int position);
}

Pero, ¿qué pasa con los flujos? Generar una respuesta de evento enviado por el servidor; con Quarkus es igual de sencillo:

@Produces(MediaType.SERVER_SENT_EVENTS)
@GET
@Path("/events")
public Multi<String> stream() {
    return kafka.toMulti();
}

Arquitecturas dirigidas por eventos

Sin embargo, las características de HTTP prohíben implementar sistemas reactivos, en los que todos los componentes interactúan utilizando el paso de mensajes asíncronos.

En primer lugar, puede consumir mensajes de varios brokers como AMQP o Apache Kafka, y procesar estos mensajes sin problemas:

@ApplicationScoped
public class MyEventProcessor {

  @Incoming("health")
  @Outgoing("heartbeat")
  public double extractHeartbeat(Health health) {
    return health.getHeartbeat();
  }
}

Las anotaciones @Incoming y @Outgoing forman parte de Mensajería Reactiva. Se utilizan para expresar desde qué canalestás consumiendo y a qué canal estás enviando. Gracias a la Mensajería Reactiva puedes consumir y enviar mensajes desde y hacia diferentes brokers y transportes como HTTP, Kafka, o Apache Camel.

A veces se necesita algo más que manejar los mensajes uno a uno. También puede expresar su lógica de procesamiento de mensajes utilizando la programación reactiva, como se ilustra en el siguiente fragmento:

@Incoming("health")
@Outgoing("output")
public Multi<Record<String, Measure> filterState(Multi<Capture> input) {
    return input
        .drop().repetitions()
        .select().where(capture -> capture.value > 0)
        .onItem().transform(capture -> new Measure(capture.sensor, capture.value, capture.unit))
        .onItem().transform(measure -> Record.of(measure.sensor, measure));
}

En cuanto a las APIs reactivas expuestas por Quarkus, la manipulación de flujos utiliza la API Mutiny.

Funciones como servicio y sin servidor

Gracias a su tiempo de inicio estelar y su bajo uso de memoria, puedes implementar funciones usando Quarkus para ser utilizadas en entornos sin servidor. Quarkus proporciona Funqy, un enfoque para escribir funciones que se pueden desplegar en varios entornos FaaS como AWS Lambda, Azure Functions, Knative y Knative Events (Cloud Events). También se puede utilizar como un servicio independiente.

Con Funqy, una función es simplemente:

import io.quarkus.funqy.Funq;

public class GreetingFunction {
    @Funq
    public String greet(String name) {
       return "Hello " + name;
    }
}

Puede utilizar cualquiera de las características de Quarkus en su función y beneficiarse de la rápida puesta en marcha y la baja utilización de la memoria. Con Quarkus, puedes abrazar este nuevo mundo sin tener que cambiar tu lenguaje de programación.