O GraphQL é frequentemente apresentado como uma maneira revolucionária de projetar APIs da Web em comparação com o REST. No entanto, se você der uma olhada mais de perto nessas tecnologias, verá que há muitas diferenças entre elas. O GraphQL é uma solução relativamente nova, cujas fontes foram abertas para a comunidade do Facebook em 2015. Hoje, o REST ainda é o paradigma mais popular usado para fornecer APIs e interoperabilidade entre microsserviços. O GraphQL poderá superar o REST no futuro? Vamos ver como ocorre a interação do microsserviço por meio da API do GraphQL usando o Spring Boot e a biblioteca
GQL .
Vamos começar com o exemplo de arquitetura do nosso sistema. Suponha que tenhamos três microsserviços que se comunicam por meio de URLs recebidas dos aplicativos Spring Cloud Eureka.

Ativando o Suporte GraphQL na Inicialização Spring
Podemos facilmente ativar o suporte ao GraphQL no lado do servidor do aplicativo Spring Boot usando iniciantes. Depois de adicionar graphql-spring-boot-starter, o servlet GraphQL estará automaticamente disponível em / graphql. Podemos substituir esse caminho padrão especificando a propriedade graphql.servlet.mapping no arquivo application.yml. Também incluímos o GraphiQL, um IDE baseado em navegador para escrever, validar e testar consultas GraphQL e a biblioteca GraphQL Java Tools, que contém componentes úteis para criar consultas e mutações. Graças a esta biblioteca, todos os arquivos no caminho de classe com a extensão .graphqls serão usados para criar uma definição 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')
Descrição do esquema GrpahQL
Cada descrição do esquema contém uma declaração de tipos, relacionamentos entre eles e muitas operações que incluem consultas para procurar objetos e mutações para criar, atualizar ou excluir dados. Geralmente, começamos definindo o tipo responsável pelo domínio do objeto descrito. Você pode indicar se o campo é obrigatório com
!
caractere ou se é uma matriz -
[…]
. A descrição deve conter o tipo declarado ou uma referência a outros tipos disponíveis na especificação.
type Employee { id: ID! organizationId: Int! departmentId: Int! name: String! age: Int! position: String! salary: Int! }
A próxima parte da definição de esquema contém declarações de consultas e mutações. A maioria das consultas retorna uma lista de objetos marcados como [Empregado] no esquema. Dentro do tipo EmployeeQueries, declaramos todos os métodos de pesquisa, enquanto no tipo EmployeeMutations, métodos para adicionar, atualizar e excluir funcionários. Se você passar um objeto inteiro para um método, declare-o como um 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 }
Implementando consultas e mutações
Graças à configuração automática das ferramentas Java do GraphQL e do Spring Boot GraphQL, não precisamos nos esforçar muito para implementar consultas e mutações em nosso aplicativo. O bean EmployeesQuery deve implementar a interface GraphQLQueryResolver. Com base nisso, o Spring poderá encontrar e chamar automaticamente o método correto como resposta a uma das consultas do GraphQL que foram declaradas dentro do esquema. Aqui está a classe que contém a implementação das respostas às 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); } }
Se você quiser chamar, por exemplo, o método employee (Long id), escreva a seguinte consulta. Para testá-lo em seu aplicativo, use o GraphiQL, disponível em / graphiql.

O bean responsável pela implementação dos métodos de mutação precisa implementar a interface GraphQLMutationResolver. Apesar do nome EmployeeInput, continuamos a usar o mesmo objeto de domínio Employee retornado pela solicitação.
@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); } }
E aqui usamos o GraphiQL para testar mutações. Aqui está um comando que adiciona um novo funcionário e aceita a resposta com o ID e o nome do funcionário.
Sobre isso, paro a tradução deste artigo e escrevo minha “digressão lírica”, mas na verdade substituo a descrição da parte do microsserviço através do Apollo Client, para interagir através das bibliotecas GQL e Unirest - bibliotecas para executar solicitações HTTP.
Cliente GraphQL no Groovy.
Para criar consultas GraphQL no microsserviço de serviço do departamento, usarei os
construtores de consultas :
String queryString = DSL.buildQuery { query('employeesByDepartment', [departmentId: departmentId]) { returns { id name position salary } } }
Essa construção no DSL GQL cria uma consulta no formato:
{ employeesByDepartment (departmentId: 1) { id name position salary } }
Além disso, executarei uma solicitação HTTP no endereço passado para o método.
Vamos descobrir como o endereço da solicitação é formado ainda mais.
(Unirest.post(serverUrl) .body(JsonOutput.toJson([query: queryString])) .asJson() .body.jsonObject['data']['employeesByDepartment'] as List) .collect { JsonUtils.jsonToData(it.toString(), Employee.class) }
Depois de receber a resposta, nós a transformamos de JSONObject na exibição de lista Funcionário.
Cliente GrpahQL para microsserviço de funcionário
Considere a implementação de funcionários de microsserviço. Neste exemplo, usei o cliente Eureka diretamente. O eurekaClient obtém todas as instâncias de serviço em execução registradas como serviço de funcionário. Em seguida, ele seleciona aleatoriamente alguma instância dentre as registradas (2). Em seguida, pega o número da porta e forma o endereço de solicitação (3) e o passa para o objeto EmployeeGQL, que é o cliente GraphQL no Groovy e descrito no parágrafo 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;
Além disso, repasso a palavra ao autor novamente, ou melhor, continuo a tradução de seu artigo.Por fim, EmployeeClient é injetado em uma classe que responde às solicitações DepartmentQueries e é usado dentro da solicitação 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 fazer as solicitações necessárias, devemos dar uma olhada no diagrama criado para o serviço de departamento. Cada objeto de departamento pode conter uma lista de funcionários designados e também definimos o tipo de funcionário referenciado pelo 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! }
Agora podemos chamar nossa consulta de teste com uma lista dos campos obrigatórios usando o GraphiQL. O aplicativo de serviço de departamento está disponível por padrão na porta 8091, ou seja, podemos vê-lo em
http: // localhost: 8091 / graphiqlConclusão
Talvez o GraphQL possa ser uma alternativa interessante à API REST padrão. No entanto, não devemos considerá-lo um substituto para o REST. Existem vários casos em que o GraphQL pode ser a melhor opção, mas aqueles em que REST é a melhor opção. Se seus clientes não precisam ter todos os campos retornados pelo lado do servidor e, além disso, você possui muitos clientes com requisitos diferentes para um ponto de entrada, o GraphQL é uma boa opção. Se você observar o que está na comunidade de microsserviços, poderá ver que agora não há uma solução baseada em Java que permita usar o GraphQL junto com a descoberta de serviços, um balanceador ou uma API de gateway pronta para uso. Neste artigo, mostrei um exemplo do uso do GQL e do Unirest para criar um cliente GraphQL com o Spring Cloud Eureka para comunicação por microsserviço. Código de exemplo para o autor de um artigo em inglês no GitHub
github.com/piomin/sample-graphql-microservices.git .
Um exemplo meu quando estiver na biblioteca GQL :
github.com/lynx-r/sample-graphql-microservices