Trong bài viết Giới thiệu về GraphQL, mình đã giới thiệu với các bạn sơ qua về cách xây dựng một GraphQL server sử dụng Spring Boot. Về bản chất thì Spring Boot đã sử dụng thư viện GraphQL Java và wrap tất cả mọi thứ behind the scenes liên quan đến việc xử lý một câu query của GraphQL của thư viện này rồi. Trong bài viết này, mình sẽ trình bày với các bạn một số kiến thức cơ bản về GraphQL và cách mà thư viện GraphQL Java xử lý một câu query như thế nào các bạn nhé!
Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:
GraphQL Java dependency như sau:
1 2 3 4 5 |
<dependency> <groupId>com.graphql-java</groupId> <artifactId>graphql-java</artifactId> <version>20.4</version> </dependency> |
Nói về GraphQL, như mình đã đề cập trong bài viết trước, chúng ta phải nói về các type. Ngoài các type định nghĩa cho các đối tượng data mà chúng ta sẽ provide cho client, ví dụ như:
1 2 3 4 5 6 7 8 |
type Student { id: ID code: String name: String age: Int address: String clazz: String } |
GraphQL còn có 3 type đặc biệt là Query, Mutation và Subscription. Trong mỗi type, chúng ta sẽ định nghĩa các fields, và trong mỗi field, chúng ta sẽ có các sub-fields. Để định nghĩa kiểu dữ liệu cho các fields hay sub-fields, các bạn có thể sử dụng các built-in scalar types https://graphql.org/learn/schema/#scalar-types, định nghĩa enum types https://graphql.org/learn/schema/#enumeration-types hoặc định nghĩa các object types như ví dụ ở trên.
Chúng ta có thể định nghĩa một field là non-null sử dụng dấu chấm than, được khai báo phía sau kiểu dữ liệu của field hoặc sub-field, ví dụ như:
1 2 3 4 5 6 7 8 |
type Student { id: ID! code: String! name: String! age: Int address: String clazz: String } |
Sub-fields id, code và name của type Student trên là non-null nha các bạn!
Chúng ta sẽ định nghĩa giá trị của field, sub-field là list sử dụng 2 dấu ngoặc vuông như sau:
1 2 3 4 5 6 7 8 9 10 11 |
type Student { id: ID code: String name: String } type Clazz { id: ID name: String students: [Student] } |
GraphQL hỗ trợ nhiều ngôn ngữ lập trình khác nhau https://graphql.org/code/ nên tuỳ nhu cầu thì các bạn có thể sử dụng cho phù hợp. Cho Java, thì như mình đã nói ở trên, chúng ta sử dụng GraphQL Java https://github.com/graphql-java/graphql-java.
Bây giờ, mình sẽ làm một ví dụ để xem cách hoạt động của GraphQL Java hoạt động như thế nào các bạn nhé!
Mình sẽ tạo mới một main class để chạy ứng dụng:
1 2 3 4 5 6 7 8 |
package com.huongdanjava.graphql; public class Application { public static void main(String[] args) { } } |
Bây giờ, mình sẽ định nghĩa một schema sử dụng type Query với nội dung đơn giản như sau:
1 2 3 4 5 |
String schema = """ type Query { hello: String } """; |
Với schema này, mình đã định nghĩa một field đơn giản là “hello”, data trả về sẽ có kiểu dữ liệu là String.
Chúng ta sẽ sử dụng đối tượng của class SchemaParser và TypeDefinitionRegistry của GraphQL Java để đọc nội dung của schema này:
1 2 |
SchemaParser schemaParser = new SchemaParser(); TypeDefinitionRegistry typeDefinitionRegistry = schemaParser.parse(schema); |
Class TypeDefinitionRegistry sẽ nắm giữ thông tin tất cả các type được định nghĩa trong tập tin schema.
Để handle cho từng request tới các type này, chúng ta sẽ sử dụng đối tượng của class RuntimeWiring. Chúng ta sẽ khởi tạo mới đối tượng RuntimeWiring và ứng với mỗi GraphQL type, chúng ta sẽ process cho từng field như sau:
1 2 3 |
RuntimeWiring runtimeWiring = RuntimeWiring.newRuntimeWiring() .type("Query", builder -> builder.dataFetcher("hello", new StaticDataFetcher("world"))) .build(); |
Như các bạn thấy, cho Query type trong ví dụ của mình, chúng ta sẽ sử dụng đối tượng TypeRuntimeWiring để handle data trả về. StaticDataFetcher implement interface DataFetcher sẽ đảm nhận data được trả về là gì. DataFetcher interface có nhiều implementation khác nhau:
Tuỳ theo nhu cầu của mình, các bạn hãy sử dụng implementation cho phù hợp nhé! Ở đây, mình sử dụng SimpleDataFetcher để trả về value mà mình khai báo khi khởi tạo đối tượng này.
Sau khi đã có đối tượng TypeDefinitionRegistry và RuntimeWiring, chúng ta cần combine chúng lại sử dụng để GraphQL engine có thể sử dụng và thực thi query cho các bạn:
1 2 |
SchemaGenerator schemaGenerator = new SchemaGenerator(); GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeDefinitionRegistry, runtimeWiring); |
Class GraphQLSchema sẽ chứa thông tin về query và cách mà ứng dụng GraphQL của chúng ta sẽ trả kết quả về.
Bây giờ là lúc GraphQL engine sẽ thực thi query cho chúng ta:
1 2 3 4 |
GraphQL build = GraphQL.newGraphQL(graphQLSchema).build(); ExecutionResult executionResult = build.execute("{hello}"); System.out.println(executionResult.getData().toString()); |
Như các bạn thấy chúng ta sẽ sử dụng đối tượng của class GraphQL được khởi tạo từ đối tượng GraphQLSchema để thực thi câu GraphQL, kết quả sẽ như sau: