lunes, 20 de julio de 2020

Apache Camel: REST CRUD y el componente SQL

Ya hicimos un post sobre Apache Camel con un mock como backend, que puedes ver aquí. Hoy veremos como cambiar ese mock por una BBDD real. 
Para empezar modificaremos las dependencias que necesitamos, tres cosas:
  • spring-boot-starter-jdbc: La librería que nos facilitará el uso de la bbdd y la creación del datasource.

  • mysql-connector-java: El driver de la BBDD.

  • camel-sql: El componente de Apache Camel que nos permitirá hacer consultas SQL. 

El siguiente paso será configurar el datasource que nos permita las conexiones con la base de datos. Esto lo podemos hacer en el fichero application.properties de Spring. 

spring.datasource.url=jdbc:mysql://localhost:3306/library?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false
spring.datasource.username=reader
spring.datasource.password=password
spring.datasource.platform=mysql
spring.datasource.initialization-mode=always

#CamelSqlGeneratedKeyRows
sql.insert=INSERT INTO BOOK (NAME, AUTHOR) VALUES (:#name, :#author)
sql.selectById=SELECT ID, NAME, AUTHOR FROM BOOK WHERE ID = :#id?outputType=SelectOne&outputClass=com.example.home.ApacheCamelRestExample.pojo.Book
sql.delete=DELETE FROM BOOK WHERE ID = :#id
sql.update=UPDATE BOOK SET NAME = :#name, AUTHOR = :#author WHERE ID = :#id

Como podeis ver tambien se han añadido las consultas que se usarán más adelante en el código.  

Vamos a empezar por un método sencillo, cambiando el mock que teníamos por una consulta SQL. Para ello utilizaremos el componente SQL de apache-camel. 

rest().get("book").produces(MediaType.APPLICATION_JSON_VALUE).route()
    .to("sql:SELECT ID, NAME, AUTHOR FROM BOOK").log("--- select all books ---");

Con el componente podremos realizar consultas directamente a BBDD haciendo uso del datasource configurado. Estas consultas podemos escribirlas directamente, o bien escribiendolas en el método o bien invocándolas desde el fichero properties con ayuda de las llaves.

rest().get("book/{id}").description("Details of an book by id").outType(Book.class)
    .produces(MediaType.APPLICATION_JSON_VALUE).route()
    .to("sql:{{sql.selectById}}").log("--- select a book ${body} ---");

En el caso anterior indicamos la salida con el método outType, lo que permitirá formatear la salida fácilmente. Para el caso de un método de tipo Insert o Delete en el cual no queremos devolver un payload podremos indicarlo con el método setBody y el código de la respuesta con setHeader.

rest().post("book").produces(MediaType.APPLICATION_JSON_VALUE).route()
    .routeId("postBookRoute").to("sql:{{sql.insert}}")
    .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(201)).setBody(constant(null));

En general es un ejemplo muy similar al que usábamos un mock por backend. Pero como vamos a usar JDBC y no JPA, las propiedades como pueden ser name o author, solo se se podrán obtener directamente desde la cabecera o el cuerpo del mensaje. Y por tanto deberemos quitar el método type, que convierte el payload de entrada en un objeto. 

rest().put("book/{id}").produces(MediaType.APPLICATION_JSON_VALUE).route()
    .choice().when()
        .simple("${header.id} < 1").bean(BookRouter.class, "negativeId")
    .otherwise()
        .to("sql:{{sql.update}}")
        .setHeader(Exchange.HTTP_RESPONSE_CODE, constant(200))
        .setBody(constant(null));

Un último truco, si queremos utilizar un pool de conexiones solo tendremos que indicarlo en el application.properties a través de la propiedad spring.datasource.type. Veremos el ejemplo con HikariCP por ejemplo:

spring.datasource.type=com.zaxxer.hikari.HikariDataSource

No hay comentarios:

Publicar un comentario