Press enter to see results or esc to cancel.

Cách sài GraphQL – Góc nhìn Frontend

Chào các bác ,

Như đã nói, em sẽ tập trung vào GraphQL trong mây bài gần đây. Trong bài viết ngắn ngủi này, em muốn giới thiệu tới các bác về cách sử dụng GraphQL duới góc nhìn của một dev frontend – GraphQL sử dụng làm sao, khác khỉ gì so với thằng Restful quen thuộc ? Cùng tìm hiểu nhé.

Demo – Playground

Ok bắt đầu vào câu chuyện nhé

Frontend: Anh ơi, gửi em URL API đê em làm Frontend nhanh không sếp chửi 

Backend: Nè chú API: http://cuthanh.com:2700/graphql Document: http://cuthanh.com:2700/graphiql 

Thế là các bác mò mẫm vào Document xem nó như thế nào

Em đã xây dựng một GraphQL API sẵn cho các bác chơi bời. GraphQL này xây dựng để thay thế cho Restful api mà mình đã nói cách xây dựng trọng loạt bài Xây dựng hệ thống gợi ý

http://cuthanh.com:2700/graphiql

Các bác vào để xem document luôn nhé

GraphQL sẽ chia thành 2 phần chính

  1. Query Các câu lệnh lấy dữ liệu (tương tự method GET trong RestFul API)
  2. Mutation Các câu lệnh để thêm/sửa dữ liệu (tuơng tự method POST/PUT/DELETE trong RestFul API)
  3. Subscription (Ơ dm thằng này không biết đếm à ) Thực ra cái này có chức năng kiểu như Emitter như bài viết bữa trước em đã nói. Client nói với Server rằng “này khi nào có thêm thăng Xmen mới thì báo cho tao nhé “. Vậy là Client đang lắng nghe server với sự kiện Thêm Xmen mới, do đó, mỗi khi có Xmen mới được thêm vào thì Server sẽ gửi Data cho Client. Bá đạo chưa, Restful làm gì có chức năng như vầy đúng không các bác. Tuy nhiên chức năng này mới chỉ đang thai nghén, và chưa được hỗ trợ chính thức . Do đó các bác ráng  đợi nhé

Query

Như trong document, query có 2 lệnh là

  1. Xmens – lấy toàn bộ danh sách các Xmen
  2. Xmen(UID: Int) – lấy thông tin của một Xmen cụ thể

Ok theo ứng dụng của chúng ta, mới vào chúng ta cần danh sách Xmen để show off ra homepage. Mà việc show off thì chỉ cần Avatar đỉnh + một cái tên cool ngầu là được (Công thức tán gái trên facebook )

Query đơn giản

Viết query

{
  Xmens {
    name
    avatar
  }
}

Ok, giờ ấn nút “Play” để “Chơi” thứ nó nhé 

{
  "data": {
    "Xmens": [
      {
        "name": "Wolverine",
        "avatar": "images/wolverine.jpg"
      },
      {
        "name": "Magneto",
        "avatar": "images/magneto.jpg"
      },
      {
        "name": "Mystique",
        "avatar": "images/mystique.jpg"
      },
      {
        "name": "Professor X",
        "avatar": "images/professorx.jpg"
      },
      {
        "name": "Quick Silver",
        "avatar": "images/quicksilver.jpg"
      }
    ]
  }
}

Kiểu vậy. Má data của em các bác làm nhoặng trong đấy nên em chỉ lấy một ít thôi . Thấy phê chưa, query thì dễ nhìn . Result trả về thì gần như y chang query ngoài việc gắn thêm data vào .

Query với tham số (argument)

Ok, bây giờ giả sử User sẽ click vào một Xmen nào đó, chúng ta sẽ phải router tới trang cá nhân của user đó và đương nhiên, phải fetch data của user đó về rồi

Vậy ta sẽ sử dụng thằng query thứ 2 Xmen(UID: Int): Xmen

Một lệnh Query viết ở Document sẽ ở dạng prototype như sau: Tên_Query(Tên_argument1: Kiểu_argument1, Tên_argument2: Kiểu_argument2):Kiểu trả về

Với document cho thằng Xmen(UID: Int): Xmen chúng ta thấy được tên query là Xmen, Argument chúng ta cần truyền vào là UID, ở kiểu Int. Thằng này sẽ trả về một kiểu gọi là kiểu Xmen. Còn kiểu Xmen như thế nào các bác ấn vào ở Document mà tự nghiền ngẫm đi nhé .

{
  Xmen(UID:1) {
    name
    avatar
    like {
      name
      avatar
    }
  }
}

Các bác chạy thử xem Kết quả làm sao nhé 

Query trong query

Có một điểm đáng chú ý ở đây là field like sẽ trả về array(Xmen), nghĩa là thằng like này lưu giữ toàn bộ thông tin những Xmen mà nhân vật Wolverine của chúng ta yêu thích. Kiểu trả về của nó sẽ y chang như kiểu mà Xmen(UID: 1) trả về. Mẹ thằng này nói khó hiểu vl , ví dụ thử coi

{
  Xmen(UID:1) {
    name
    avatar
    like {
      name
      like {
        name
        avatar
        like {
          name
        }
      }
    }
  }
}

Câu lệnh trên nghĩa là sao các bác.

  • Nghĩa là nó sẽ lấy thông tin (name, avatar, like) của Xmen có UID bằng 1 (Thằng Wolverine đấy)
  • Tiếp theo ta sẽ lấy thông tin (nam, like) của tất cả những thằng Xmen được Wolverine yêu thích  (VD có n thằng trả về)
  • Tiếp nữa, chúng ta lại lấy thông tin (name, avatar, like) của tất cả những thằng được Xmen được Wolverine yêu thích yêu thích  (Vd có m thằng trả về)
  • Cuối cúng, chúng ta lấy thông tin (name) của tất cả những thằng Xmen được Wolverine yêu thích yêu thích yêu thích.  (Vd có k thằng trả về)
  • Done! (response) trả về gì các bác tự xem nhé. 

Haha fuck your mind =))

Thử tượng tượng xem, nếu chúng ta dùng Rest thì phải làm sao. Chúng ta query /1. Đợi response trả về, lấy field like query tiếp n thằng nữa. Ứng với mỗi n ta sẽ query m lần nữa. Cuối cùng, ứng với mỗi m ta phải query k lần nữa.

Vậy là tổng cộng 1 + n*m*k lần phải query.

Đặc biệt hơn nữa, các bác phải đợi thằng trước trả kết quả rồi mới có thể query thằng sau. Trong khi với GraphQL, fortunately, chúng ta chỉ cần query đúng 1 lần. Thêm nữa, với Restful, mỗi lần query sẽ trả về full field của một xmen (_id, UID, name, avatar, date, like, _v). Với GraphQL chúng ta chỉ cần lấy field nào chúng ta cần. Ez 

Tới đây bạn đã thấy thằng GraphQL này bá đạo cỡ nào chưa . Với ví dụ trên thôi, theo mình GraphQL đã chạy nhanh hơn Restful API mấy trăm lần rồi.

Batch Request

Chưa hết, GraphQL còn hỗ trợ Batch Request (cái này chúng bên Restful chúng ta cũng làm được nhưng mệt mỏi lắm, do đó các bác sẽ rất ít được gặp nó)

Batch Request là gì, nghĩa là request nhiều query cúng một lúc. Ví dụ trong ứng dụng của chúng ta, có một trang cần cả thông tin của 1 Xmen cụ thể, cần cả thông tin của danh sách Xmen nữa, giờ sao? 

{
  Xmens {
    name
    avatar
  }
  Xmen(UID:1) {
    name
    avatar
    like {
      name
    }
  }
}

Aliases

Vâng, với việc hỗ trợ Batch Request luôn thì chúng ta lại nảy sinh một vài vấn đề nữa (Cái này gọi là nợ mẹ đẻ nợ con )

Nếu chúng ta cần Query lấy thông tin của Xmen có UID 1 và Xmen có UID là 2 thì sao

{
  Xmen(UID:1) {
    name
    avatar
    like {
      name
    }
  }
  Xmen(UID:2) {
    name
    avatar
    like {
      name
    }
  }
}

Các bác thử copy rồi ấn nút “Chơi” thử coi 

Lỗi đúng không. Hehe . Vì khi trả data về, server tương đương lắp data vào những field chúng ta query. Nhưng trong câu Query trên, có 2 field Xmen ở cùng cấp nên nó đị conflict (mâu thuẫn với nhau), làm sao có 2 field trong cùng một object (Javascript) được, đúng không các bác . Dù sao, các bác cũng query câu trên thử đi, server sẽ ném vào mặt các bác câu lỗi Fields \"Xmen\" conflict because they have differing arguments.

Use different aliases on the fields to fetch both if this was intentional.

Nghĩa là chúng ta nên đặt tên khác/bí danh (aliases) để giải quyết vấn đề. Đặt aliases làm sao? Xem bên dưới

{
  ThangA: Xmen(UID:1) {
    name
    avatar
    like {
      name
    }
  }
  ThangB: Xmen(UID:2) {
    name
    avatar
    like {
      name
    }
  }
}

Đấy, vậy là lại có Response ngon lành , chả lỗi lầm khỉ gì cả.

Nâng cao – Operation Name, Directive, Variable

Ok, giờ nâng cao thêm xíu nữa nhể.

query getXmen($input:Int!, $getLike: Boolean!) {
  Xmen(UID:$input) {
    name
    like @include(if: $getLike) {
      UID
      name
      avatar
      date
    }
  }
}
{
  "input": 1,
  "getLike": false
}

Đầu tiên, ta thấy được dòng query getXmen($input:Int!, $getLike: Boolean!) khá lạ huh ? Cái này là định nghĩa một function các mẹ ạ (hay đại loại kiểu vậy), thằng GraphQL gọi nó là Operation, em thích gọi là Function . Okey, function thì phải có input – các argument. Và argument bắt đầu bằng kí hiệu $ (giống định nghĩa variable trong PHP nhỉ).

Mục đính viết function vào đấy làm gì? Reusable. Function giúp chúng ta chạy một đống câu lệnh bên trong mà mỗi lần sử dụng không phải viết lại từng câu lệnh và đối với GraphQL cùng để là dễ Debug nữa (Document của GraphQL viết vậy, em vẫn méo thấy dễ chỗ nào cả vì cũng chưa gặp Bug). 

Ta định nghĩa Query ở trên, giá trị variable ở một nơi khác. Nó giống như định nghĩa một function, còn mỗi khi gọi nó ta lại pass argument khác nhau tuỳ trường hợp vậy. Giúp code của các bác dễ quản lý hơn.

Điều đặc biệt thứ 2 là đoạn like @include(if: $getLike) Đoạn này có nghĩa là chỉ Get field like nếu giá trị $getLiketrue. Khá hay phải không? Và ngược lại với @include chúng ta có @skip(if: $variable_in_bool_type), thằng @skip này hoạt động ngược lại với thằng @include. Nói chung chỉ cần biết một thằng thôi là đủ rồi, nhẹ não .

Ngoài các kiểu Query mà mình đã nói bên trên, còn một số định nghĩa khác về Fragments, Meta Type nữa. Mình sẽ đề cập vào lần sau tại vì 2 thằng này chỉ thực sự phát huy công dụng tốt khi chúng ta làm việc với React/ReactNative và định nghĩa Type trong GraphQL phức tạp thôi .

Tạm thời vậy đã.

Mutation

Một ứng dụng, trong thực tế, sẽ không chỉ có việc Fetch data từ server về. Nó cần phải có những thay đổi, thêm bớt và gửi lên server nữa. Để làm việc này, GraphQL tách ra thành nhánh Mutation.

Có một điều quan trọng em phải nhắc các bác trước. Mutation luôn luôn phải đặt trong một function.

mutation addAXmen($input: XmenInput!) {
  addXmen(input:$input) {
    name
    avatar
  }
}
{
  "input": {
    "name": "Cu's Thanh's",
    "avatar": "https://graph.facebook.com/100003217152910/picture?type=large"
  }
}

Cách để thêm một Xmen Cu’s Thanh’s vào data của chúng ta. Các bác chú ý một điều nữa là nếu mutation nào chúng ta sử dụng mà cần argument not null (Có dấu ! ở đằng sau đấy), thì khi định nghĩa function, chúng ta cũng phải cần thêm dấu ! vào định nghĩa kiểu của variable nhé. Một dấu ! thôi mà cũng em điên đầu mấy tiếng đấy 

Một mutation thì có thể trả về kết quả. Còn kết quả kiểu gì thì các bác tự đọc document đi nhá. Của em là kiểu Xmen, do đó, chúng ta cũng thể nói với GraphQL là, “bố chỉ cần những field x, field y thôi nhé con trai… 

Subcription

Phần này em chưa code, và GraphQL cũng chưa có phương án giải quyết chính thức cho thằng này . Vì thế các bác đợi bài sau nhé.

Kết bài

Qua đây, dưới góc nhìn của Frontend thì thấy sao các bác. Đối với em thì thấy sướng quá, query cực kì thích, trực quan. Lại còn không phải xây dựng một đống query lằng nhằng, thằng này đợi thằng kia nữa chứ 

Document thì khá là phê (em đánh giá là 8/10).

Về phần Mutation thì đúng thực là hơi nhằng hơn so với Restful một xíu, nhưng không sao, vẫn ngon lành ha .

Từ đấy, thấy rằng GraphQL thực sự là một bước tiến so với Restful. Nó cực kì tiết kiệm thời gian cho frontend, và cả tài nguyên cho User nữa (không phải vêu mồm chờ response ).

Còn các bác, các bác thấy GraphQL có thực sự nuột như em nói không, còn chỗ nào sida? Comment bên dưới nhé!

Like
Like Love Haha Wow Sad Angry
1961
Comments

2 Comments

con của tía

đọc xong méo hiểu cái mẹ gì luôn tía à

Minh Thành

Tiếng miên đấy con ơi =]]


Leave a Comment