GraphQL est souvent présenté comme un moyen révolutionnaire de concevoir des API Web par rapport à REST. Cependant, si vous regardez de plus près ces technologies, vous verrez qu'il y a beaucoup de différences entre elles. GraphQL est une solution relativement nouvelle, dont les sources ont été ouvertes à la communauté Facebook en 2015. Aujourd'hui, REST est toujours le paradigme le plus populaire utilisé pour fournir des API et l'interopérabilité entre les microservices. GraphQL pourra-t-il dépasser REST à l'avenir? Voyons comment l'interaction des microservices se produit via l'API GraphQL à l'aide de Spring Boot et de la bibliothèque
GQL .
Commençons par l'exemple d'architecture de notre système. Supposons que nous ayons trois microservices qui communiquent entre eux via des URL reçues des applications Spring Cloud Eureka.

Activation de la prise en charge de GraphQL dans Spring Boot
Nous pouvons facilement activer la prise en charge de GraphQL du côté serveur de l'application Spring Boot à l'aide de démarreurs. Après avoir ajouté graphql-spring-boot-starter, le servlet GraphQL sera automatiquement disponible dans / graphql. Nous pouvons remplacer ce chemin par défaut en spécifiant la propriété graphql.servlet.mapping dans le fichier application.yml. Nous incluons également GraphiQL, un IDE basé sur un navigateur pour écrire, valider et tester des requêtes GraphQL et la bibliothèque GraphQL Java Tools, qui contient des composants utiles pour créer des requêtes et des mutations. Grâce à cette bibliothèque, tous les fichiers du chemin de classe avec l'extension .graphqls seront utilisés pour créer une définition de schéma.
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')
Description du schéma GrpahQL
Chaque description du schéma contient une déclaration des types, des relations entre eux et de nombreuses opérations qui incluent des requêtes pour rechercher des objets et des mutations pour créer, mettre à jour ou supprimer des données. Nous commençons généralement par définir le type responsable du domaine de l'objet décrit. Vous pouvez indiquer si le champ est obligatoire avec
!
ou s'il s'agit d'un tableau -
[…]
. La description doit contenir le type déclaré ou une référence à d'autres types disponibles dans la spécification.
type Employee { id: ID! organizationId: Int! departmentId: Int! name: String! age: Int! position: String! salary: Int! }
La partie suivante de la définition de schéma contient des déclarations de requêtes et de mutations. La plupart des requêtes renvoient une liste d'objets marqués comme [Employé] dans le schéma. Dans le type EmployeeQueries, nous déclarons toutes les méthodes de recherche, tandis que dans le type EmployeeMutations, les méthodes pour ajouter, mettre à jour et supprimer des employés. Si vous passez un objet entier à une méthode, vous devez le déclarer comme type d'entrée.
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 }
Implémentation de requêtes et de mutations
Grâce à la configuration automatique de GraphQL Java Tools et Spring Boot GraphQL, nous n'avons pas besoin de faire beaucoup d'efforts pour implémenter des requêtes et des mutations dans notre application. Le bean EmployeesQuery doit implémenter l'interface GraphQLQueryResolver. Sur cette base, Spring pourra automatiquement rechercher et appeler la bonne méthode en réponse à l'une des requêtes GraphQL qui ont été déclarées dans le schéma. Voici la classe contenant l'implémentation des réponses aux requêtes:
@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 vous souhaitez appeler, par exemple, la méthode employee (Long id), écrivez la requête suivante. Pour le tester dans votre application, utilisez GraphiQL, disponible sur / graphiql.

Le bean responsable de l'implémentation des méthodes de mutation doit implémenter l'interface GraphQLMutationResolver. Malgré le nom EmployeeInput, nous continuons à utiliser le même objet de domaine Employee qui est renvoyé par la demande.
@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); } }
Et ici, nous utilisons GraphiQL pour tester les mutations. Voici une commande qui ajoute un nouvel employé et accepte la réponse avec l'ID et le nom de l'employé.
À ce sujet, je suspends la traduction de cet article et écris ma «digression lyrique», mais remplace en fait la description de la partie microservice via le client Apollo, pour interagir via les bibliothèques GQL et Unirest - bibliothèques pour exécuter les requêtes HTTP.
Client GraphQL sur Groovy.
Pour créer des requêtes GraphQL dans un microservice au service du service, j'utiliserai des
générateurs de requêtes :
String queryString = DSL.buildQuery { query('employeesByDepartment', [departmentId: departmentId]) { returns { id name position salary } } }
Cette construction sur DSL GQL crée une requête de la forme:
{ employeesByDepartment (departmentId: 1) { id name position salary } }
Et, en outre, je vais effectuer une requête HTTP à l'adresse transmise à la méthode.
Nous découvrirons comment l’adresse de demande est encore développée.
(Unirest.post(serverUrl) .body(JsonOutput.toJson([query: queryString])) .asJson() .body.jsonObject['data']['employeesByDepartment'] as List) .collect { JsonUtils.jsonToData(it.toString(), Employee.class) }
Après avoir reçu la réponse, nous la transformons de JSONObject en vue Liste des employés.
Client GrpahQL pour le microservice des employés
Envisagez la mise en œuvre d'employés de microservices. Dans cet exemple, j'ai utilisé directement le client Eureka. eurekaClient obtient toutes les instances de service en cours enregistrées en tant que service d'employé. Il sélectionne ensuite au hasard une instance parmi celles enregistrées (2). Ensuite, il prend son numéro de port et forme l'adresse de demande (3) et la transmet à l'objet EmployeeGQL qui est le client GraphQL sur Groovy et qui est décrit dans le paragraphe précédent.
@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;
De plus, je «refile» le mot à l'auteur, ou plutôt je continue la traduction de son article.Enfin, EmployeeClient est injecté dans une classe qui répond aux demandes DepartmentQueries et est utilisé dans la demande departmentByOrganizationWithEmployees.
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; }
Avant de faire les demandes nécessaires, nous devons jeter un œil au schéma créé pour le département-service. Chaque objet Department peut contenir une liste d'employés affectés, et nous avons également défini le type Employee référencé par le type Department.
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! }
Nous pouvons maintenant appeler notre requête de test avec une liste des champs obligatoires à l'aide de GraphiQL. L'application département-service est disponible par défaut sur le port 8091, c'est-à-dire que nous pouvons la voir sur
http: // localhost: 8091 / graphiqlConclusion
GraphQL peut être une alternative intéressante à l'API REST standard. Cependant, nous ne devons pas le considérer comme un remplacement de REST. Il existe plusieurs cas où GraphQL peut être le meilleur choix, mais ceux où REST est le meilleur choix. Si vos clients n'ont pas besoin que tous les champs soient renvoyés par le côté serveur, et que vous avez en outre de nombreux clients avec des exigences différentes pour un point d'entrée, alors GraphQL est un bon choix. Si vous regardez ce qui se trouve dans la communauté des microservices, vous pouvez voir qu'il n'y a maintenant aucune solution basée sur Java qui vous permet d'utiliser GraphQL avec la découverte de service, un équilibreur ou une API de passerelle prête à l'emploi. Dans cet article, j'ai montré un exemple d'utilisation de GQL et Unirest pour créer un client GraphQL avec Spring Cloud Eureka pour la communication de microservices. Exemple de code pour l'auteur d'un article en anglais sur GitHub
github.com/piomin/sample-graphql-microservices.git .
Un de mes exemples avec la bibliothèque GQL :
github.com/lynx-r/sample-graphql-microservices