Desarrollado por Facebook y publicado como un estándar abierto para que todos lo usen, GraphQL está pensado como una alternativa a las API REST. Al igual que REST, GraphQL proporciona una forma de crear y consumir API basadas en la web, pero las consultas y los datos devueltos utilizan esquemas formales y un sistema de tipos para garantizar la coherencia. En este artículo, repasaremos los conceptos básicos del diseño e implementación de una API GraphQL y analizaremos muchas de las consideraciones y decisiones clave que tomará durante el proceso. Lenguajes y marcos GraphQL Si planea usar GraphQL como su API de aplicación web, es muy probable que el lenguaje y los componentes de datos que ya está usando respalden sus esfuerzos. Las bibliotecas GraphQL están disponibles para casi todos los lenguajes principales en uso de producción. Los clientes están disponibles para C#/.NET, Go, Java y Android, JavaScript, Swift/Objective-C y Python, y las bibliotecas de servidor cubren aún más terreno. Si está comenzando completamente desde cero, es mejor que elija el lenguaje, el entorno de ejecución y la capa de datos con los que esté más familiarizado de otros proyectos. El uso de GraphQL no impone muchas restricciones en el servidor o cliente, y es independiente de la base de datos. Sin embargo, es posible que deba realizar una integración más o menos manual de su capa de datos según cuál sea. (Más sobre esto en la siguiente sección). Usaremos la implementación de Python de GraphQL como referencia en este artículo. Los conceptos y la funcionalidad serán más o menos los mismos para otros lenguajes. Esquema de consulta de datos de GraphQL GraphQL acepta consultas construidas a partir de campos fuertemente tipados en varias disposiciones jerárquicas. La parte de la creación de una API de GraphQL en la que debe pensar más es qué esquema proporcionar para las consultas. En muchos casos, los campos de consulta se pueden mapear uno a uno a una fuente de datos subyacente, para exponer todos los campos relevantes en la base de datos (u otra fuente de datos) para sus consultas. Debido a que las consultas GraphQL pueden ser considerablemente más abiertas y variadas que sus contrapartes REST, debe planificar desde el principio qué campos se pueden consultar y cómo se asignarán a su base de datos. Por ejemplo, si tenemos una tabla de base de datos para películas, con los campos título y año (como un entero), podríamos usar una consulta GraphQL como esta: type Character { title: String! year: Int } El ! después de String significa que un campo determinado es obligatorio, por lo que necesitaríamos al menos un título para realizar esta consulta. También debe asegurarse de que los campos que exponga a través de GraphQL usen tipos que coincidan correctamente con los datos subyacentes. Por ejemplo, GraphQL no tiene un tipo de datos nativo «fecha» o «fecha y hora», en gran parte debido a la gran diversidad de implementaciones disponibles. Si desea permitir búsquedas por rangos de fechas, deberá aplicar el formato de las fechas tal como se toman a través de la API y también asegurarse de que esas solicitudes de fecha se traduzcan a sus contrapartes adecuadas para la base de datos de back-end cuando la consulte. Dependiendo del marco que esté utilizando, es posible que este trabajo ya se haya realizado por usted. Graphene, una biblioteca GraphQL popular para Python, proporciona valores de fecha y hora con formato ISO-8601 como un tipo nativo, por lo que no tiene que lidiar con eso usted mismo. Si su conjunto de datos tiene muchos campos, comience por exponer el subconjunto funcional más pequeño de esos campos que no requieren imposiciones de tipos complejas, por ejemplo, consultas numéricas o de cadenas simples. Luego, puede expandir gradualmente los campos disponibles a medida que descubre cómo implementar consultas para ellos a través del conector GraphQL que está utilizando. Almacenamiento y recuperación de datos GraphQLEl almacenamiento y la recuperación de datos de su back-end normalmente utilizan el middleware compatible con la biblioteca GraphQL para su lenguaje. En muchos casos, puede hacer que GraphQL realice este trabajo a través de capas de datos para marcos de aplicaciones comunes. La biblioteca Graphene de Python para GraphQL, por ejemplo, admite el marco web Django, junto con el ORM integrado de Django. Graphene también admite el ORM SQLAlchemy y agregó compatibilidad con los populares marcos Starlette y FastAPI. También puede interoperar con los conectores de datos de Google App Engine y el marco de JavaScript Relay (utilizado por React). Si está utilizando una capa de datos que no está descrita por ninguno de estos componentes, puede utilizar el middleware de Graphene y los objetos DataLoader para cerrar la brecha. Estos le brindan lugares para conectar manualmente la integración que necesita con su capa de datos. Con DataLoader, tiene una manera de fusionar múltiples solicitudes simultáneas de datos relacionados y, por lo tanto, reducir la cantidad de viajes de ida y vuelta a su back-end. Nada de esto, por cierto, le impide realizar el almacenamiento en caché usted mismo en cualquier capa de la aplicación. Por ejemplo, las respuestas que devuelve se pueden almacenar en caché mediante un proxy, mientras que los datos del back-end se pueden almacenar en caché mediante Memcached o Redis. Dicho esto, sería su responsabilidad asegurarse de que esos cachés se expulsen cada vez que cambien los datos. Consultas y mutaciones de GraphQL GraphQL utiliza un formato de consulta específico, llamado «consulta de mutación», para crear, actualizar o eliminar elementos de un conjunto de datos. Piense en la forma en que funcionarán estas consultas: no solo qué consultas permitirá y qué campos requerirá para ellas, sino también qué datos devolverá de la consulta después de la mutación. Cuando diseña una consulta de mutación, puede permitir la devolución de cualquier cantidad de campos de salida. Dicho esto, probablemente no sea una buena idea anidar objetos de respuesta en más de una o dos capas de profundidad, ya que eso hace que los resultados sean difíciles de analizar, tanto al observar la consulta en sí como al escribir código para manejar los resultados. Otra advertencia importante es no dejar que los viejos hábitos de diseño de API REST dicten la forma en que organiza sus consultas de mutación. Por ejemplo, en lugar de crear múltiples consultas de mutación para manejar diferentes tipos de cambios en el mismo objeto (un patrón común en REST), podría consolidarlas en una sola consulta de mutación. Una forma de hacerlo sería usar campos distintos y no opcionales para registrar cada operación posible, como el «voto positivo/voto negativo» en este ejemplo. Otra sería usar un campo de valor más un tipo de enumeración para describir el comportamiento deseado con ese valor. Una gran ventaja de una enumeración es que es inequívoca: puede usarla para reflejar la intención con precisión, por lo que es altamente autodocumentada. Hay una buena posibilidad de que la biblioteca GraphQL de su lenguaje le brinde una forma de usar enumeraciones que sea consistente con la implementación del concepto del lenguaje. Por ejemplo, las enumeraciones GraphQL en Graphene para Python pueden parecerse mucho a la clase de enumeración de la biblioteca estándar de Python. Almacenamiento en caché de GraphQL y aceleración del rendimiento En el fondo, una consulta GraphQL sondea y recupera datos de la misma manera que cualquier otra consulta. Eso significa que se puede acelerar con muchos de los mismos métodos que se usan para acelerar las API de consulta: Almacenamiento en caché: cualquier servicio que tenga una base de datos como back-end o que devuelva datos desde un front-end puede beneficiarse del almacenamiento en caché en ambos extremos. Tenga en cuenta que la responsabilidad de hacer expirar esas cachés recae sobre usted, por lo que probablemente tendrá que usar los ganchos de middleware del marco GraphQL (como los descritos anteriormente para Graphene) para activar tales cosas. Se recomienda que use identificadores únicos siempre que sea posible para admitir el almacenamiento en caché del lado del cliente. Cursores y paginación: Una solicitud debe tener un límite superior predeterminado para la cantidad de registros que devuelve a la vez, para evitar que tanto el cliente como el servidor se inunden. También tiene sentido permitir que los clientes describan explícitamente la cantidad máxima de registros que se devolverán y qué «página» de registros solicitar. La documentación oficial de GraphQL tiene algunos consejos útiles sobre cómo integrar metáforas de paginación en el formato de solicitud GraphQL. Herramientas GraphQL Además de las bibliotecas disponibles para varios lenguajes, GraphQL tiene una gran cantidad de herramientas nativas y de terceros para facilitar el desarrollo de clientes, servidores, esquemas y capas de procesamiento de consultas: Apollo GraphQL dedica sus recursos a crear herramientas de código abierto para GraphQL, incluidos clientes GraphQL y servidores GraphQL. También mantiene GraphQL Tools, un conjunto de utilidades para generar y simular esquemas GraphQL y «unir» múltiples API en una sola API, llevando a cabo la misión declarada de GraphQL de consolidar múltiples puntos finales de API y hacerlos más manejables. Si está pensando en trasladar una API existente generada por Swagger a GraphQL, la herramienta Swagger2GraphQL fue creada para esta tarea. También permite el mantenimiento en paralelo de una API heredada generada por Swagger, de modo que puede utilizar ambos estándares durante un período de transición. Por último, el propio grupo GraphQL de Facebook tiene algunas herramientas que vale la pena destacar. GraphiQL es un IDE en el navegador para crear consultas GraphQL; se puede utilizar internamente o como una solución pública. También hay una implementación de GraphQL en JavaScript, un conjunto de servidores y clientes GraphQL sobre HTTP y un servicio de lenguaje GraphQL para IDE. Copyright © 2024 IDG Communications, Inc.