GraphQL wird häufig als revolutionäre Methode zum Entwerfen von Web-APIs im Vergleich zu REST vorgestellt. Wenn Sie sich diese Technologien jedoch genauer ansehen, werden Sie feststellen, dass es viele Unterschiede zwischen ihnen gibt. GraphQL ist eine relativ neue Lösung, deren Quellen 2015 für die Facebook-Community geöffnet wurden. REST ist bis heute das beliebteste Paradigma für APIs und Interoperabilität zwischen Microservices. Wird GraphQL in Zukunft REST überholen können? Lassen Sie uns sehen, wie die Microservice-Interaktion über die GraphQL-API mithilfe von Spring Boot und der
GQL- Bibliothek erfolgt.
Beginnen wir mit dem Architekturbeispiel unseres Systems. Angenommen, wir haben drei Microservices, die über URLs miteinander kommunizieren, die von Spring Cloud Eureka-Anwendungen empfangen werden.

Aktivieren der GraphQL-Unterstützung im Spring Boot
Wir können die Unterstützung von GraphQL auf der Serverseite der Spring Boot-Anwendung mithilfe von Startern problemlos aktivieren. Nach dem Hinzufügen von graphql-spring-boot-Starter ist das GraphQL-Servlet automatisch unter / graphql verfügbar. Wir können diesen Standardpfad überschreiben, indem wir die Eigenschaft graphql.servlet.mapping in der Datei application.yml angeben. Wir enthalten auch GraphiQL, eine browserbasierte IDE zum Schreiben, Validieren und Testen von GraphQL-Abfragen sowie die GraphQL Java Tools-Bibliothek, die nützliche Komponenten zum Erstellen von Abfragen und Mutationen enthält. Dank dieser Bibliothek werden alle Dateien im Klassenpfad mit der Erweiterung .graphqls zum Erstellen einer Schemadefinition verwendet.
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')
Beschreibung des GrpahQL-Schemas
Jede Beschreibung des Schemas enthält eine Deklaration von Typen, Beziehungen zwischen ihnen und viele Vorgänge, die Abfragen zum Suchen nach Objekten und Mutationen zum Erstellen, Aktualisieren oder Löschen von Daten enthalten. Normalerweise definieren wir zunächst den Typ, der für die Domäne des beschriebenen Objekts verantwortlich ist. Sie können mit angeben, ob das Feld benötigt wird
!
Zeichen oder wenn es ein Array ist -
[…]
. Die Beschreibung muss den deklarierten Typ oder einen Verweis auf andere in der Spezifikation verfügbare Typen enthalten.
type Employee { id: ID! organizationId: Int! departmentId: Int! name: String! age: Int! position: String! salary: Int! }
Der nächste Teil der Schemadefinition enthält Deklarationen von Abfragen und Mutationen. Die meisten Abfragen geben eine Liste von Objekten zurück, die im Schema als [Mitarbeiter] markiert sind. Innerhalb des EmployeeQueries-Typs deklarieren wir alle Suchmethoden, während im EmployeeMutations-Typ Methoden zum Hinzufügen, Aktualisieren und Löschen von Mitarbeitern vorhanden sind. Wenn Sie ein gesamtes Objekt an eine Methode übergeben, müssen Sie es als Eingabetyp deklarieren.
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 }
Abfragen und Mutationen implementieren
Dank der automatischen Konfiguration von GraphQL Java Tools und Spring Boot GraphQL müssen wir keine großen Anstrengungen unternehmen, um Abfragen und Mutationen in unserer Anwendung zu implementieren. Die EmployeesQuery-Bean muss die GraphQLQueryResolver-Schnittstelle implementieren. Auf dieser Grundlage kann Spring die richtige Methode als Antwort auf eine der im Schema deklarierten GraphQL-Abfragen automatisch finden und aufrufen. Hier ist die Klasse, die die Implementierung der Antworten auf Abfragen enthält:
@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); } }
Wenn Sie beispielsweise die Methode employee (Long id) aufrufen möchten, schreiben Sie die folgende Abfrage. Verwenden Sie GraphiQL, das unter / graphiql verfügbar ist, um es in Ihrer Anwendung zu testen.

Die Bean, die für die Implementierung der Mutationsmethoden verantwortlich ist, muss die GraphQLMutationResolver-Schnittstelle implementieren. Trotz des Namens EmployeeInput verwenden wir weiterhin dasselbe Employee-Domänenobjekt, das von der Anforderung zurückgegeben wird.
@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); } }
Und hier verwenden wir GraphiQL, um Mutationen zu testen. Hier ist ein Befehl, der einen neuen Mitarbeiter hinzufügt und die Antwort mit der ID und dem Namen des Mitarbeiters akzeptiert.
In diesem Zusammenhang unterbreche ich die Übersetzung dieses Artikels und schreibe meinen „lyrischen Exkurs“, ersetze jedoch die Beschreibung des Microservice-Teils über den Apollo-Client, um über die GQL- und Unirest-Bibliotheken zu interagieren - Bibliotheken zum Ausführen von HTTP-Anforderungen.
GraphQL-Client auf Groovy.
Um GraphQL-Abfragen im abteilungsdienstlichen Microservice zu erstellen, verwende ich
Abfrage-Builder :
String queryString = DSL.buildQuery { query('employeesByDepartment', [departmentId: departmentId]) { returns { id name position salary } } }
Diese Konstruktion in DSL GQL erstellt eine Abfrage des Formulars:
{ employeesByDepartment (departmentId: 1) { id name position salary } }
Außerdem werde ich eine HTTP-Anforderung an die an die Methode übergebene Adresse ausführen.
Wir finden heraus, wie die Anforderungsadresse weiter gebildet wird.
(Unirest.post(serverUrl) .body(JsonOutput.toJson([query: queryString])) .asJson() .body.jsonObject['data']['employeesByDepartment'] as List) .collect { JsonUtils.jsonToData(it.toString(), Employee.class) }
Nachdem wir die Antwort erhalten haben, transformieren wir sie von JSONObject in die Mitarbeiterlistenansicht.
GrpahQL-Client für Mitarbeiter-Microservice
Betrachten Sie die Implementierung von Microservice-Mitarbeitern. In diesem Beispiel habe ich den Eureka-Client direkt verwendet. Mit eurekaClient werden alle laufenden Dienstinstanzen als Mitarbeiter-Service registriert. Dann wählt er zufällig eine Instanz aus den registrierten aus (2). Als nächstes nimmt es seine Portnummer und bildet die Anforderungsadresse (3) und übergibt sie an das EmployeeGQL-Objekt, das der GraphQL-Client auf Groovy ist und das im vorherigen Absatz beschrieben wurde.
@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;
Außerdem „gebe“ ich das Wort erneut an den Autor weiter oder setze die Übersetzung seines Artikels fort.Schließlich wird EmployeeClient in eine Klasse eingefügt, die auf DepartmentQueries-Anforderungen antwortet und innerhalb der Anforderung "departmentByOrganizationWithEmployees" verwendet wird.
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; }
Bevor wir die erforderlichen Anfragen stellen, sollten wir uns das Diagramm ansehen, das für den Abteilungsservice erstellt wurde. Jedes Abteilungsobjekt kann eine Liste der zugewiesenen Mitarbeiter enthalten. Außerdem haben wir den Mitarbeitertyp definiert, auf den der Abteilungstyp verweist.
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! }
Jetzt können wir unsere Testabfrage mit einer Liste der erforderlichen Felder mit GraphiQL aufrufen. Die Abteilung-Service-Anwendung ist standardmäßig auf Port 8091 verfügbar,
dh wir können sie unter
http: // localhost: 8091 / graphiql sehenFazit
Vielleicht ist GraphQL eine interessante Alternative zur Standard-REST-API. Wir sollten es jedoch nicht als Ersatz für REST betrachten. Es gibt mehrere Fälle, in denen GraphQL die beste Wahl ist, aber diejenigen, in denen REST die beste Wahl ist. Wenn Ihre Clients nicht alle Felder von der Serverseite zurückgeben müssen und Sie außerdem viele Clients mit unterschiedlichen Anforderungen für einen Einstiegspunkt haben, ist GraphQL eine gute Wahl. Wenn Sie sich ansehen, was sich in der Microservice-Community befindet, können Sie feststellen, dass es jetzt keine Java-basierte Lösung gibt, mit der Sie GraphQL zusammen mit der Serviceerkennung, einem Balancer oder einer sofort einsatzbereiten Gateway-API verwenden können. In diesem Artikel habe ich ein Beispiel für die Verwendung von GQL und Unirest zum Erstellen eines GraphQL-Clients mit Spring Cloud Eureka für die Microservice-Kommunikation gezeigt. Beispielcode für den Autor eines Artikels in englischer Sprache auf GitHub
github.com/piomin/sample-graphql-microservices.git .
Ein Beispiel von mir mit der GQL- Bibliothek :
github.com/lynx-r/sample-graphql-microservices