1. Gambaran keseluruhan
GraphQL adalah bahasa pertanyaan, yang dibuat oleh Facebook dengan tujuan membina aplikasi pelanggan berdasarkan sintaks intuitif dan fleksibel, untuk menerangkan keperluan dan interaksi data mereka.
Salah satu cabaran utama dengan panggilan REST tradisional adalah ketidakupayaan pelanggan untuk meminta sekumpulan data yang disesuaikan (terhad atau diperluas). Dalam kebanyakan kes, apabila pelanggan meminta maklumat dari pelayan, ia mendapat semua atau tidak ada bidang.
Kesukaran lain adalah bekerja dan mengekalkan beberapa titik akhir. Apabila platform berkembang, akibatnya jumlahnya akan bertambah. Oleh itu, pelanggan sering perlu meminta data dari titik akhir yang berbeza.
Semasa membina pelayan GraphQL, hanya perlu memiliki satu URL untuk semua pengambilan dan mutasi data. Oleh itu, pelanggan boleh meminta sekumpulan data dengan mengirimkan rentetan pertanyaan, menjelaskan apa yang mereka inginkan, ke pelayan.
2. Tatanama Grafik Asas
Mari kita perhatikan terminologi asas GraphQL.
- Pertanyaan: adalah operasi baca sahaja yang diminta ke pelayan GraphQL
- Mutasi: adalah operasi baca-tulis yang diminta ke pelayan GraphQL
- Resolver: Dalam GraphQL, Resolver bertanggungjawab untuk memetakan operasi dan kod yang berjalan di backend yang bertanggung jawab untuk menangani permintaan tersebut. Ia serupa dengan backend MVC dalam aplikasi RESTFul
- Jenis A Jenis mentakrifkan bentuk data tindak balas yang boleh dikembalikan dari pelayan GraphQL, termasuk bidang yang tepi untuk lain Jenis
- Input: seperti Jenis, tetapi menentukan bentuk data input yang dihantar ke pelayan GraphQL
- Skalar: adalah Jenis primitif , seperti String , Int , Boolean , Float , dll
- Antaramuka: Antaramuka akan menyimpan nama bidang dan argumen mereka, sehingga objek GraphQL dapat mewarisi darinya, memastikan penggunaan bidang tertentu
- Skema: Dalam GraphQL, Skema menguruskan pertanyaan dan mutasi, menentukan apa yang dibenarkan untuk dilaksanakan di pelayan GraphQL
2.1. Memuatkan Skema
Terdapat dua cara memuatkan skema ke pelayan GraphQL:
- dengan menggunakan Bahasa Definisi Antaramuka (IDL) GraphQL
- dengan menggunakan salah satu bahasa pengaturcaraan yang disokong
Mari tunjukkan contoh menggunakan IDL:
type User { firstName: String }
Sekarang, contoh definisi skema menggunakan kod Java:
GraphQLObjectType userType = newObject() .name("User") .field(newFieldDefinition() .name("firstName") .type(GraphQLString)) .build();
3. Bahasa Definisi Antara Muka
Interface Definition Language (IDL) atau Schema Definition Language (SDL) adalah kaedah yang paling ringkas untuk menentukan Skema GraphQL. Sintaksnya ditentukan dengan baik dan akan diguna pakai dalam Spesifikasi GraphQL rasmi.
Sebagai contoh, mari kita buat skema GraphQL untuk Pengguna / E-mel dapat ditentukan seperti ini:
schema { query: QueryType } enum Gender { MALE FEMALE } type User { id: String! firstName: String! lastName: String! createdAt: DateTime! age: Int! @default(value: 0) gender: [Gender]! emails: [Email!]! @relation(name: "Emails") } type Email { id: String! email: String! default: Int! @default(value: 0) user: User @relation(name: "Emails") }
4. GraphQL-java
GraphQL-java adalah implementasi berdasarkan spesifikasi dan pelaksanaan rujukan JavaScript. Perhatikan bahawa ia memerlukan sekurang-kurangnya Java 8 untuk berjalan dengan baik.
4.1. Anotasi GraphQL-java
GraphQL juga memungkinkan untuk menggunakan anotasi Java untuk menghasilkan definisi skema tanpa semua kod boilerplate yang dibuat dengan penggunaan pendekatan IDL tradisional.
4.2. Kebergantungan
Untuk membuat contoh kami, mari mula-mula mula mengimport kebergantungan yang diperlukan yang bergantung pada modul Graphql-java-anotasi:
com.graphql-java graphql-java-annotations 3.0.3
Kami juga menerapkan perpustakaan HTTP untuk mempermudah penyiapan dalam aplikasi kami. Kami akan menggunakan Ratpack (walaupun dapat diimplementasikan juga dengan Vert.x, Spark, Dropwizard, Spring Boot, dll.).
Mari juga import kebergantungan Ratpack:
io.ratpack ratpack-core 1.4.6
4.3. Pelaksanaan
Mari buat contoh kami: API sederhana yang menyediakan "CRUDL" (Buat, Ambil, Kemas kini, Hapus, dan Senaraikan) untuk pengguna. Pertama, mari buat POJO Pengguna kami :
@GraphQLName("user") public class User { @GraphQLField private Long id; @GraphQLField private String name; @GraphQLField private String email; // getters, setters, constructors, and helper methods omitted }
Dalam POJO ini kita dapat melihat anotasi @GraphQLName ("pengguna") , sebagai petunjuk bahawa kelas ini dipetakan oleh GraphQL bersama dengan setiap bidang yang diberi penjelasan dengan @GraphQLField.
Seterusnya, kami akan membuat kelas UserHandler . Kelas ini mewarisi dari pustaka penyambung HTTP yang dipilih (dalam kes kami, Ratpack) kaedah pengendali, yang akan mengurus dan menggunakan ciri Penyelesai GraphQL . Oleh itu, mengarahkan permintaan (muatan JSON) ke operasi pertanyaan atau mutasi yang betul:
@Override public void handle(Context context) throws Exception { context.parse(Map.class) .then(payload -> { Map parameters = (Map) payload.get("parameters"); ExecutionResult executionResult = graphql .execute(payload.get(SchemaUtils.QUERY) .toString(), null, this, parameters); Map result = new LinkedHashMap(); if (executionResult.getErrors().isEmpty()) { result.put(SchemaUtils.DATA, executionResult.getData()); } else { result.put(SchemaUtils.ERRORS, executionResult.getErrors()); LOGGER.warning("Errors: " + executionResult.getErrors()); } context.render(json(result)); }); }
Sekarang, kelas yang akan menyokong operasi pertanyaan, iaitu UserQuery. Seperti yang telah disebutkan, semua kaedah pengambilan data dari pelayan ke klien dikendalikan oleh kelas ini:
@GraphQLName("query") public class UserQuery { @GraphQLField public static User retrieveUser( DataFetchingEnvironment env, @NotNull @GraphQLName("id") String id) { // return user } @GraphQLField public static List listUsers(DataFetchingEnvironment env) { // return list of users } }
Similarly to UserQuery, now we create UserMutation, which will manage all the operations that intend to change some given data stored on the server side:
@GraphQLName("mutation") public class UserMutation { @GraphQLField public static User createUser( DataFetchingEnvironment env, @NotNull @GraphQLName("name") String name, @NotNull @GraphQLName("email") String email) { //create user information } }
It is worth notice the annotations in both UserQuery and UserMutation classes: @GraphQLName(“query”) and @GraphQLName(“mutation”). Those annotations are used to define the query and mutation operations respectively.
With the GraphQL-java server able to run the query and mutation operations, we can use the following JSON payloads to test the request of the client against the server:
- For the CREATE operation:
{ "query": "mutation($name: String! $email: String!){ createUser (name: $name email: $email) { id name email age } }", "parameters": { "name": "John", "email": "[email protected]" } }
As the response from the server for this operation:
{ "data": { "createUser": { "id": 1, "name": "John", "email": "[email protected]" } } }
- For the RETRIEVE operation:
{ "query": "query($id: String!){ retrieveUser (id: $id) {name email} }", "parameters": { "id": 1 } }
As the response from the server for this operation:
{ "data": { "retrieveUser": { "name": "John", "email": "[email protected]" } } }
GraphQL menyediakan ciri-ciri yang dapat disesuaikan oleh pelanggan. Jadi, dalam operasi RETRIEVE terakhir yang digunakan sebagai contoh, daripada mengembalikan nama dan e-mel, kita boleh, sebagai contoh, hanya mengembalikan e-mel:
{ "query": "query($id: String!){ retrieveUser (id: $id) {email} }", "parameters": { "id": 1 } }
Jadi, maklumat yang dikembalikan dari pelayan GraphQL hanya akan mengembalikan data yang diminta:
{ "data": { "retrieveUser": { "email": "[email protected]" } } }
5. Kesimpulan
GraphQL adalah cara yang mudah dan cukup menarik untuk meminimumkan kerumitan antara klien / pelayan sebagai pendekatan alternatif untuk REST API.
Seperti biasa, contohnya terdapat di repositori GitHub kami.