-->
ads here

Simple Guidance For You In GraphQL

advertise here
Xin chào mọi người, đến hẹn lại lên, tháng 9 này mình sẽ trở lại với mọi người một bài viết về technical nhé. Và hôm nay chung ta sẽ tìm hiểu về một công nghệ của Facebook giúp chúng ta có thể viết được JSON API thay thế cho RESTful truyền thống mà rất phổ biến. Và công nghệ đó có tên là GraphQL, một cái tên gợi nhớ đến ngôn ngữ truy vấn - Query Language. Và để hiểu rõ hơn về GraphQL thì chúng ta sẽ lần lượt tìm hiểu qua các mục sau:
  1. What is GraphQL?
  2. Why we should use GraphQL?
  3. GraphQL vs REST 
  4. Basic concepts and syntax
Ok, Let's do it!

1. What is GraphQL?

Truy cập vào trang chủ của GrapQL (QGL) tại graphQL.org  ta có thể thấy được định nghĩa của GQL.
GraphQL là một ngôn ngữ truy vấn dành cho API và là server-side runtime để hoàn thành các truy vấn trên dữ liệu. GQL mô tả đầy đủ và dễ hiểu về dữ liệu trên API, cho phép client có thể yêu cầu chính xác những dữ liệu mà họ cần, không thừa, không thiếu.


GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
Một số tính năng đặc trưng của GraphQL:

Ask for what you need, get exactly that

Khi gửi đi 1 GQL query, client sẽ nhận chính xác những dữ liệu họ cần, không thừa không thiếu. Dữ liệu trả về của một truy vấn luôn luôn dự đoán trước được. Những ứng dụng sử dụng GQL thường sẽ nhanh và ổn định vì bản thân control được những dữ liệu nó nhận được chứ không phải server.

Get many resources in a single request

GQL không chỉ truy xuất được vào những đặc tính của resource và còn có thể kéo theo những resource khác thông qua những reference. Khác với REST API phải cần đến nhiều URL, GQL có thể lấy toàn bộ dữ liệu mà ứng dụng cần thông qua chỉ 1 request duy nhất. Do đó những ứng dụng sử dụng GQL có thể lấy dữ liệu nhanh chóng dù trong điều kiện mạng chậm

Describe what's possible with a type system

Thay vì sử dụng nhiều endpoint, GQL được tổ chức dưới dạng typefield, vì vậy GQL có khả năng truy cập toàn bộ dữ liệu thông qua 1 endpoint duy nhất. GQL sử dụng 1 type system để đảm bảo việc Apps chỉ yêu cầu những gì khả thi và tránh việc parse dữ liệu trong code. Đồng thời GQL cũng cấp những error rõ ràng và có ích.

Evolve your API without version

Việc thêm 1 type hay field mới vào GQL API sẽ không hề ảnh hưởng đến những truy vấn đang tồn tại. Điều này tương tự khi một field nào đó đã bị cũ, out-of-date thì nó sẽ không được dùng nữa và bị ẩn đi. Bằng việc chỉ sử dụng 1 version của API (single evolving version), GQL cho phép App luôn có thể sử dụng những tính năng mới đồng thời giúp code trên server rõ ràng và dễ bảo trì hơn

Bring your own data and code

GQL tạo ra một API đồng nhất trên toàn bộ ứng dụng mà không hề bị giới hạn bởi bất kì storage engine nào. Bạn có thể hiện thực ứng dụng của mình với rất nhiều ngôn ngữ đã hỗ trợ GQL.

Playground

GQL còn cung cấp một công cụ giúp phát triển ứng dụng GQL nhanh hơn gọi là GraphiQL. Bạn có thể xem thêm  và tải về GraphiQL tại đây.

2. Why we should use GraphQL?

Vậy vì sao chúng ta nên sử dụng GraphQL?
  • GraphQL cho phép client tuỳ chỉnh tập dữ liệu mà client muốn nhận, client chỉ cần mô tả những thông tin mình cần thông qua query string, sau đó gửi lên server thì sẽ nhận được chính xác những gì client yêu cầu
  • GQL cho phép truy cập dữ liệu thông qua 1 endpoint duy nhất vì GQL được tổ chức dưới dạng các type và field
Kết luận: khi xây dựng 1 GQL server, bạn chỉ cần duy nhất 1 URL cho cả việc lấy dữ liệu cũng như thay đổi dữ liệu (fetching and mutating data)

3. REST APIs vs GraphQL APIs

Trong phần này, chúng ta sẽ so sánh một số điểm nổi bật giữa REST và GQL,
  1. Điểm khác biệt đầu tiên là về bản chất của REST và GQL:
    • Trong khi REST được hiểu là một khái niệm về kiến trúc (Architectural concept) được dùng cho những phần mềm sử dụng mạng. Nó được thiết kế để tách biệt API ra khỏi client
    • GQL là một ngôn ngữ truy vấn được thiết kế để vận hành trên 1 endpoint duy nhất thông qua HTTP và hướng để mục tiêu performance và flexibility cho client
  2. Về resource: REST và GQL khác nhau ở điểm việc mô tả resource không nhất thiết phải gắn liền với cách ta lấy được resource đó.
    • REST: mỗi URL sẽ là định danh của resource, ví dụ bạn muốn lấy thông tin của 1  cuốn sách, bạn cần dùng URL /book/<id_of_the_book>
    • GQL: định danh của resource tách biệt hẳn với cách lấy nó
  3. URLs vs GQL Schema: Ở REST, dữ liệu truy xuất được sẽ được mô tả qua danh sách các endpoint, còn GQL, thì được mô tả thông quan mối quan hệ giữa các schema
    • Ở REST, khi muốn chuyển từ lấy dữ liệu sang tạo 1 dữ liệu mới bạn phải đổi HTTP verb từ GET thành POST (hay bất kì từ khác như PUT, DELETE...)
    • GQL: bạn chuyển đổi từ fetching sang mutating thông qua keyword trong câu truy vấn
Vẫn còn có những điểm khác nhau khác giữa 2 ứng viên này, trên đây mình chỉ viết ra những điềm mà mình cho rằng nó nổi bật nhất.

4. Basic concepts and syntax

Tiếp theo chúng ta sẽ lần lượt tìm hiểu một số khái niệm cũng như cú pháp cơ bản của GraphQL

4.1. Field

Về căn bản, trong GQL, fiel là những trường cụ thể trong object mà được yêu cầu bởi client thông qua GQL. Ta có thể thêm xem ví dụ bên dưới về 1 truy vấn về tên của user và kết qủa trả về của truy vấn đó
 {  
   user {  
     name  
   }  
 }  

 {  
  "data": {  
   "user": {  
    "name": "Julian"  
   }  
  }  
 }  

Ví dụ về 1 query với các field là user và name, đồng thời là kết quả trả về của query đó
Như ta có thể thấy, kết quả trả về có cùng mô hình như của câu truy vấn. Đây chính là điều thuộc về bản chất của GQL: sẽ luôn nhận được chính xác những gì mà bạn yêu cầu vì server biết chính xác client cần có những field j để trả về.

4.2. Argument

Trong GQL cho phép mỗi field và các object lồng bên trong nó được truyền tham số vào, giúp cho GQL có thể hoàn toàn thay thế việc tạo ra các fetch API. Trong khi đó, nếu dùng REST, ta chỉ có thể truyền argument thông qua query parameter và URL segment
{  
  human(id: "1000") {  
   name  
   height(unit: FOOT)  
  }  
 }  
Query

 {  
  "data": {  
   "human": {  
    "name": "Luke Skywalker",  
    "height": 5.6430448  
   }  
  }  
 }  
Result

4.3. Alisases

Ta có thể thấy, các field trong kết quả sẽ khớp tương ứng với các field trong query, nhưng không bao gồm các argument. Vậy nên ta không thể trực tiếp yêu cầu cùng 1 field với nhiều argument khác nhau. Vì vây alisas ra rời giúp ta có thể đặt lại tên cho kết quả của 1 field nào đó.
Như ví dụ trên, kết quả của field hero đã được đặt lại tên dựa trên argument episode.

{  
  empireHero: hero(episode: EMPIRE) {  
   name  
  }  
  jediHero: hero(episode: JEDI) {  
   name  
  }  
 }  
Query

{  
  "data": {  
   "empireHero": {  
    "name": "Luke Skywalker"  
   },  
   "jediHero": {  
    "name": "R2-D2"  
   }  
  }  
 }  
Result

4.4. Fragment

Hãy lấy ví dụ ở trên, giả sử thay vì có 1 field là name ta cần nhiều hơn như sau: 

{  
     empireHero: hero(episode: EMPIRE) {   
         name  
         age  
         gender  
     }   
      jediHero: hero(episode: JEDI) {   
         name   
         age  
         gender  
      }   
 }   
Khi đó ta sẽ bị lặp lại các trường name, age, gender ở câu truy vấn. Do đó Fragment ra đời giúp ta hạn chế việc lặp lại ở trên. Khi đó câu query của chúng ta sẽ trở thành:

{  
     empireHero: hero(episode: EMPIRE) {   
           ...fragmentFields  
     }   
      jediHero: hero(episode: JEDI) {   
           ...fragmentFields  
      }   
 }   
 fragment fragmentFields on Hero {  
    name    
    age   
    gender  
 }  

4.5. Operation name

Operation name đơn giản là tên của một tác vụ và luôn đi kèm với type của nó (query hoặc mutation hoặc subscription. Ví dự như sau:

query UserName {   
   user {   
    name   
   }   
  }   
Trong đó query là kiểu của tác vụ và UserName là tên của tác vụ đó

4.6. Variable

Cách sử dụng variable như sau:
  • Trong câu truy vấn, gía trị tĩnh được thay bằng $<tên_variable>, ở đây sẽ là $id
  • Sau đó khai báo $<tên_variable> ($id) vào câu truy vấn
  • Truyền giá trị cho biến dưới dạng <tên_variable>: value.
// Query with variable  
 query UserName($id: Int) {  
   user(id:$id) {    
   name    
   }    
  }  
 // Pass value  
 {  
   id: 1  
 }  
 GQL cho phép truyền default variable, khi đó, ta có thể thực hiện query mà không cần variable, và query sẽ được thực hiện ứng với default variable

4.7. Directives

Directive cho phép thay đổi định dạng cũng như cấu trúc của câu truy vấn thông qua variable. Có 2 loại directive là @include@skip
  • @include (if: Boolean) : chỉ đính kèm trường này vào kết quả nếu giá trị của argument là true
  • @skip (if: Boolean): bỏ qua trường này nếu giá trị của argument là true
Ví dụ:

// Non-directive query  
 query UserInfo($id: Int){  
     user(id:$id){  
         name  
         age  
         gender  
     }  
 }  
Non-directive query

// With @include  
 query UserInfo($id: Int, $withAge: Boolean!){  
     user(id:$id){  
         name  
         age @include(if: $withAge)  
         gender  
     }  
 }  
 // Pass value   
 {  
     id: 1,  
     withAge: false  
 }  
 // Result  
 {  
     "data": {  
         "name": "Julian Dong",  
         "gender": "F"  
     }  
 }  
With include directive

4.8. Mutation

Nếu query là tác vụ để fetch data từ server thì mutation là tác dụng dùng để tạo, xoá và update data.
Ví dụ như ta muốn tạo 1 user mới và trả về thông tin của user vừa được tạo, ta sẽ viết 1 mutation như sau:

mutation createNewUser($name, $age, $gender = "Male") {  
  createUser(name: $name, age: $age) {  
   id  
  }  
 }  
 // Variable  
 {  
     name: "Julian Dong",  
     age: 24,  
 }  
 // Result  
 {  
     "data": {  
         "createUser": {  
             "name": "Julian Dong"  
             "age": 24,  
             "gender": "Male"  
         }  
     }  
 }  

Reference

Advertisement
COMMENTS ()