Recuperar datos eficientemente en GraphQL usando batching con data loaders
Escrito por
el , actualizado el .
java
planeta-codigo
programacion
Enlace permanente
Comentarios
Al diferencia de una API REST donde cada recurso posee un endpoint propio en GraphQL los recursos están relacionados y forman un grafo. Por otro lado las propiedades devueltas en una consulta de GraphQL son las que se indiquen en la consulta en vez de prefijadas como en una API REST. Hay que tener en cuenta que GraphQL para recuperar las propiedades de las entidades usa un resolver y las recupera una a una, si se devuelve una lista de elementos y de cada uno de esos elementos otra propiedad para la que hay que generar una consulta adicional a la base de datos el rendimiento no será bueno. Los data loaders permiten recuperar las propiedades relacionadas de una colección de entidades eficientemente evitando el problema 1+N.
Una de las dificultades a resolver en GraphQL es evitar los problemas de generar 1+N consultas dado que en algunas peticiones se recupera una lista de elementos para recuperar alguna otra propiedad de esos elementos para la que se realiza otra consulta. Suele ocurrir al navegar las relaciones de las entidades, por ejemplo al solicitar una lista de libros y de cada libro obtener su autor, para obtener los libros se necesita una consulta y hay que evitar que para recuperar el autor de cada libro generar otra consulta, si el número de libros recuperados es grande el número de consultas será grande y la consulta será poco eficiente, lenta y generará una carga a evitar en el servidor de base de datos.
En el artículo Recuperar datos eficientemente en GraphQL usando batching comentaba una estrategia para evitar este problema que consistía en dados una serie de elementos recuperados y si la propiedad estaba presente en la consulta se obtenían los identificativos de esos elementos y se recuperaba la propiedad para todos los elementos en una única consulta.
Sin embargo, GraphQL posee otra estrategia para resolver el problema de los 1+N, mediante Data Loaders. Para usar un data loader en una propiedad de un tipo hay que crear una clase que implemente la interfaz MappedBatchLoader o MappedBatchLoaderWithContext de java-loader. El método a implementar es load(Set<K>) que recibe un conjunto de instancias de las que se quiere recuperar la propiedad y devuelve un Map<K,V> cuya clave es la instancia de la colección y el valor de la propiedad recuperada.
|
|
Una vez definidos los data loaders hay que incluirlos en un registro e indicarlos en la clase del contexto de GraphQL. El método contextBuilder recibe todas las instancias de data loaders, el método dataLoaderRegistry crea el registro y finalmente se asigna el registro al contexto. Los data loaders cachean los datos de modo que si los datos no se deben compartir entre peticiones hay que construir los data loaders en cada petición.
|
|
Una vez creados los data loaders hay que usarlos en los resolver de las propiedades de una entidad en la que se desee que se cargue de forma batched. El método de la propiedad del resolver debe devolver un CompletableFuture, el método recibe la instancia de la que se quiere recuperar una propiedad y una referencia de DataFetchingEnvironment de la librería graphql-java, se recupera el data loader de esa propiedad y se le indica que acumule el conjunto de instancias de las que se quiere recuperar. GraphQL en algún momento llamará al método load(Set<K>) que recibe un conjunto de instancias para realizar la carga de todas en una única consulta.
|
|
Al obtener los datos del conjunto de libros que utilizan un batch loader se produce la siguiente salida.
|
|
El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:./gradlew run