GraphQL a menudo se presenta como una forma revolucionaria de diseñar API web en comparación con REST. Sin embargo, si observa más de cerca estas tecnologías, verá que hay muchas diferencias entre ellas. GraphQL es una solución relativamente nueva, cuyas fuentes se abrieron a la comunidad de Facebook en 2015. Hoy, REST sigue siendo el paradigma más popular utilizado para proporcionar API e interoperabilidad entre microservicios. ¿GraphQL podrá superar a REST en el futuro? Veamos cómo se produce la interacción de microservicios a través de la API GraphQL utilizando Spring Boot y la biblioteca
GQL .
Comencemos con el ejemplo de arquitectura de nuestro sistema. Supongamos que tenemos tres microservicios que se comunican entre sí a través de las URL recibidas de las aplicaciones Spring Cloud Eureka.

Habilitación de la compatibilidad con GraphQL en Spring Boot
Podemos habilitar fácilmente el soporte para GraphQL en el lado del servidor de la aplicación Spring Boot usando iniciadores. Después de agregar graphql-spring-boot-starter, el servlet GraphQL estará disponible automáticamente en / graphql. Podemos anular esta ruta predeterminada especificando la propiedad graphql.servlet.mapping en el archivo application.yml. También incluimos GraphiQL, un IDE basado en navegador para escribir, validar y probar consultas GraphQL y la biblioteca GraphQL Java Tools, que contiene componentes útiles para crear consultas y mutaciones. Gracias a esta biblioteca, todos los archivos en el classpath con la extensión .graphqls se usarán para crear una definición de esquema.
compile('com.graphql-java:graphql-spring-boot-starter:5.0.2') compile('com.graphql-java:graphiql-spring-boot-starter:5.0.2') compile('com.graphql-java:graphql-java-tools:5.2.3')
Descripción del esquema GrpahQL
Cada descripción del esquema contiene una declaración de tipos, relaciones entre ellos y muchas operaciones que incluyen consultas para buscar objetos y mutaciones para crear, actualizar o eliminar datos. Por lo general, comenzamos definiendo el tipo responsable del dominio del objeto descrito. Puede indicar si el campo es obligatorio con
!
carácter o si es una matriz -
[…]
. La descripción debe contener el tipo declarado o una referencia a otros tipos disponibles en la especificación.
type Employee { id: ID! organizationId: Int! departmentId: Int! name: String! age: Int! position: String! salary: Int! }
La siguiente parte de la definición del esquema contiene declaraciones de consultas y mutaciones. La mayoría de las consultas devuelven una lista de objetos que están marcados como [Empleado] en el esquema. Dentro del tipo EmployeeQueries, declaramos todos los métodos de búsqueda, mientras que en el tipo EmployeeMutations, métodos para agregar, actualizar y eliminar empleados. Si pasa un objeto completo a un método, debe declararlo como un tipo de entrada.
schema { query: EmployeeQueries mutation: EmployeeMutations } type EmployeeQueries { employees: [Employee] employee(id: ID!): Employee! employeesByOrganization(organizationId: Int!): [Employee] employeesByDepartment(departmentId: Int!): [Employee] } type EmployeeMutations { newEmployee(employee: EmployeeInput!): Employee deleteEmployee(id: ID!) : Boolean updateEmployee(id: ID!, employee: EmployeeInput!): Employee } input EmployeeInput { organizationId: Int departmentId: Int name: String age: Int position: String salary: Int }
Implementación de consultas y mutaciones
Gracias a la configuración automática de GraphQL Java Tools y Spring Boot GraphQL, no necesitamos hacer un gran esfuerzo para implementar consultas y mutaciones en nuestra aplicación. El bean EmployeesQuery debe implementar la interfaz GraphQLQueryResolver. En base a esto, Spring podrá encontrar y llamar automáticamente al método correcto como respuesta a una de las consultas GraphQL que se han declarado dentro del esquema. Aquí está la clase que contiene la implementación de las respuestas a las consultas:
@Component public class EmployeeQueries implements GraphQLQueryResolver { private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeQueries.class); @Autowired EmployeeRepository repository; public List employees() { LOGGER.info("Employees find"); return repository.findAll(); } public List employeesByOrganization(Long organizationId) { LOGGER.info("Employees find: organizationId={}", organizationId); return repository.findByOrganization(organizationId); } public List employeesByDepartment(Long departmentId) { LOGGER.info("Employees find: departmentId={}", departmentId); return repository.findByDepartment(departmentId); } public Employee employee(Long id) { LOGGER.info("Employee find: id={}", id); return repository.findById(id); } }
Si desea llamar, por ejemplo, al método de empleado (Identificación larga), escriba la siguiente consulta. Para probarlo en su aplicación, use GraphiQL, que está disponible en / graphiql.

El bean responsable de implementar los métodos de mutación necesita implementar la interfaz GraphQLMutationResolver. A pesar del nombre EmployeeInput, seguimos utilizando el mismo objeto de dominio Employee que devuelve la solicitud.
@Component public class EmployeeMutations implements GraphQLMutationResolver { private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeQueries.class); @Autowired EmployeeRepository repository; public Employee newEmployee(Employee employee) { LOGGER.info("Employee add: employee={}", employee); return repository.add(employee); } public boolean deleteEmployee(Long id) { LOGGER.info("Employee delete: id={}", id); return repository.delete(id); } public Employee updateEmployee(Long id, Employee employee) { LOGGER.info("Employee update: id={}, employee={}", id, employee); return repository.update(id, employee); } }
Y aquí usamos GraphiQL para probar mutaciones. Aquí hay un comando que agrega un nuevo empleado y acepta la respuesta con la identificación y el nombre del empleado.
Sobre esto, detengo la traducción de este artículo y escribo mi "digresión lírica", pero en realidad reemplazo la descripción de la parte del microservicio a través del Apollo Client para interactuar a través de las bibliotecas GQL y Unirest, bibliotecas para ejecutar solicitudes HTTP.
Cliente GraphQL en Groovy.
Para crear consultas GraphQL en microservicios de servicio de departamento, utilizaré los
constructores de consultas :
String queryString = DSL.buildQuery { query('employeesByDepartment', [departmentId: departmentId]) { returns { id name position salary } } }
Esta construcción en DSL GQL crea una consulta del formulario:
{ employeesByDepartment (departmentId: 1) { id name position salary } }
Y, además, realizaré una solicitud HTTP en la dirección pasada al método.
Descubriremos cómo se forma aún más la dirección de solicitud.
(Unirest.post(serverUrl) .body(JsonOutput.toJson([query: queryString])) .asJson() .body.jsonObject['data']['employeesByDepartment'] as List) .collect { JsonUtils.jsonToData(it.toString(), Employee.class) }
Después de recibir la respuesta, la transformamos de JSONObject a la vista de lista de Empleados.
Cliente GrpahQL para microservicio de empleados
Considere la implementación de empleados de microservicios. En este ejemplo, utilicé el cliente Eureka directamente. eurekaClient obtiene todas las instancias de servicio en ejecución registradas como servicio de empleado. Luego, selecciona aleatoriamente alguna instancia de las registradas (2). A continuación, toma su número de puerto y forma la dirección de solicitud (3) y la pasa al objeto EmployeeGQL que es el cliente GraphQL en Groovy y que se describe en el párrafo anterior.
@Component public class EmployeeClient { private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeClient.class); private static final String SERVICE_NAME = "EMPLOYEE-SERVICE"; private static final String SERVER_URL = "http://localhost:%d/graphql"; Random r = new Random(); @Autowired private EurekaClient discoveryClient;
Además, "paso" la palabra al autor nuevamente, o más bien continúo la traducción de su artículo.Finalmente, EmployeeClient se inyecta en una clase que responde a las solicitudes de DepartmentQueries y se usa dentro de la solicitud de departamentosByOrganizationWithEmployees.
public List<Department> departmentsByOrganizationWithEmployees(Long organizationId) { LOGGER.info("Departments find: organizationId={}", organizationId); List<Department> departments = repository.findByOrganization(organizationId); for (int i = 0; i < departments.size(); i++) { departments.get(i).setEmployees(employeeClient.findByDepartment(departments.get(i).getId())); } return departments; }
Antes de hacer las solicitudes necesarias, debemos echar un vistazo al diagrama creado para el servicio de departamento. Cada objeto del Departamento puede contener una lista de empleados asignados, y también definimos el tipo de Empleado al que hace referencia el tipo de Departamento.
schema { query: DepartmentQueries mutation: DepartmentMutations } type DepartmentQueries { departments: [Department] department(id: ID!): Department! departmentsByOrganization(organizationId: Int!): [Department] departmentsByOrganizationWithEmployees(organizationId: Int!): [Department] } type DepartmentMutations { newDepartment(department: DepartmentInput!): Department deleteDepartment(id: ID!) : Boolean updateDepartment(id: ID!, department: DepartmentInput!): Department } input DepartmentInput { organizationId: Int! name: String! } type Department { id: ID! organizationId: Int! name: String! employees: [Employee] } type Employee { id: ID! name: String! position: String! salary: Int! }
Ahora podemos llamar a nuestra consulta de prueba con una lista de los campos obligatorios usando GraphiQL. La aplicación de servicio de departamento está disponible de forma predeterminada en el puerto 8091, es decir, podemos verla en
http: // localhost: 8091 / graphiqlConclusión
Quizás GraphQL puede ser una alternativa interesante a la API REST estándar. Sin embargo, no debemos considerarlo como un reemplazo para REST. Hay varios casos en los que GraphQL puede ser la mejor opción, pero aquellos en los que REST es la mejor opción. Si sus clientes no necesitan tener todos los campos devueltos por el lado del servidor, y además tiene muchos clientes con diferentes requisitos para un punto de entrada, GraphQL es una buena opción. Si observa lo que hay en la comunidad de microservicios, puede ver que ahora no hay una solución basada en Java que le permita usar GraphQL junto con el descubrimiento de servicios, un equilibrador o una API de puerta de enlace lista para usar. En este artículo, mostré un ejemplo del uso de GQL y Unirest para crear un cliente GraphQL con Spring Cloud Eureka para la comunicación de microservicios. Código de muestra para el autor de un artículo en inglés en GitHub
github.com/piomin/sample-graphql-microservices.git .
Un ejemplo mío cuando estoy con la biblioteca GQL :
github.com/lynx-r/sample-graphql-microservices