---
description: https://topdev.vn/blog/graphql/
---

# \[GRAPHQL] GraphQL – Công nghệ mới cho web developer

### GraphQL là gì? <a href="#graphql-la-gi" id="graphql-la-gi"></a>

**GraphQL** là một cú pháp mô tả cách yêu cầu lấy dữ liệu, và thường được dùng để load data từ một server cho client.



> GraphQL bao gồm 3 điểm đặc trưng bao gồm cho phép client xác định chính xác những gì dữ liệu họ cần, làm cho việc tổng hợp dữ liệu từ nhiều nguồn dễ dàng hơn và nó sử dụng một type system để mô tả dữ liệu.

![](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql_diagram.jpg)

### Vấn đề <a href="#van-de" id="van-de"></a>

GraphQL bắt đầu từ ông lớn Facebook, thế nhưng ngay cả những app đơn giản đôi khi vẫn gặp phải trường hợp “nghẽn cổ chai” do sự hạn chế của REST APIs.

&#x20;Thí dụ bạn muốn hiển thị một list `posts`, và ở dưới mỗi `post` là một list `like`, bao gồm cả tên người dùng và avatar. Cách giải quyết đơn giản là thay đổi API của ‘posts’ để nó bao gồm a ‘like’ array chứa thông tin về người dùng.



![graphql](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql-1.png)

&#x20;Thế nhưng khi làm như vậy cho các app mobile thì bạn sẽ phát hiện ra tốc độ của chúng chạy quá chậm. Vì thế mà giờ đây bạn sẽ cần tới 2 endpoints, một với `likes`và một thiếu chúng.

&#x20;Giờ thì còn có thêm một vấn đề khác xuất hiện: trong khi `posts`được lưu trữ trong một MySQL database thì `likes` lại được lưu tại Redis store! Bạn biết mình phải làm gì trong trường hợp nào không?

Mở rộng vấn đề trên ra với việc Facebook phải quản lí vô số data source và API clients thì cũng là điều dễ hiểu khi REST APIs bị đánh giá là cũ kĩ bởi những hạn chế của nó.

### Giải pháp <a href="#giai-phap" id="giai-phap"></a>

Giải pháp mà Facebook đưa ra đến từ một ý tưởng rất đơn giản: Thay vì có đến hàng tá “endpoint” ngu ngốc, sao lại không dùng chỉ một “endpoint” thông minh với khả năng tiếp thu những Query phức tạp rồi đưa ra output data với loại type tùy theo yêu cầu của client.

Thế tế mà nói, GraphQL như là một layer nằm giữa client và data source, sau khi nhận yêu cầu của client thì nó sẽ kiếm những thông tin cần từ các data source và đưa lại cho client theo format họ muốn. Vẫn chưa hiểu? Thế thì đến lúc dùng ví dụ ẩn dụ rồi đây!

Như bạn thấy đấy, REST model cũ giống y như việc bạn đặt cái bánh Pizza, rồi gọi ship hàng online và kêu bên tiệm giặt ủi đem đồ đến cho bạn. Tất cả diễn ra với 3 cuộc gọi và 3 cửa hàng.

![graphql](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql1.png)

GraphQL mặt khác lại giống như là thư kí riêng của bạn vậy: Sau khi bạn đưa địa chỉ của 3 cửa hàng và nói yêu cầu của bạn thì GraphQL sẽ làm hết mọi chuyện còn lại trong khi bạn chỉ việc chờ chúng được chuyển đến cho mình.

![graphql](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql2.png)

Nói cách khác GraphQL tạo ra một ngôn ngữ chuẩn (standard language) để thực hiện những công việc này.

![graphql](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql3.png)

GraphQL API được tạo ra từ 3 phần chính: **schema**, **queries**, và **resolvers**

#### **Queries** <a href="#queries" id="queries"></a>

Những yêu cầu bạn đặt ra cho thư kí của mình, GraphQL, được gọi là query và nó giống như thế này:

```
query {
  stuff
}
```

&#x20;Chúng ta tuyên bố một ‘query’ mới sử dụng keyword `query` , và đặt tên cho field đó là `stuff`. Điều thú vị của GraphQLquery là có support các nested fields. Thế nên chúng ta có thể đi sâu vào hơn:

```
query {
  stuff {
    eggs
    shirt
    pizza
  }
}
```

Như bạn thấy đấy, client khi đưa ra những yêu cầu và tạo ra query sẽ không cần lo data đến từ source nào. Chỉ việc hỏi và GraphQLserver sẽ lo hết mọi thứ khác.

&#x20;Cũng đáng lưu ý là việc các query field còn có khả năng chỉ đến các **array**

```
query {
  posts { # this is an array
    title
    body
    author { # we can go deeper!
      name
      avatarUrl
      profileUrl
    }
  }
}
```

&#x20;Query field còn support cả **argument.** Nếu bạn muốn đưa ra một post riêng, thì chỉ cần thêm `id` argument cho `post` field.

```
query {
  post(id: "123foo"){
    title
    body
    author{
      name
      avatarUrl
      profileUrl
    }
  }
}
```

&#x20;Cuối cùng, nếu bạn còn muốn `id` argument đó đặc biệt hơn, bạn có thể tạo ra một **variable** và tái sử dụng chúng bên trong query (nhớ là ta phải đặt tên cái query đó luôn)

```
query getMyPost($id: String) {
  post(id: $id){
    title
    body
    author{
      name
      avatarUrl
      profileUrl
    }
  }
}
```

Một cách thực hành khá tốt là sử dụng [GitHub’s GraphQLAPI Explorer](https://developer.github.com/early-access/graphql/explorer/). Hãy thử query sau:

```
query {
  repository(owner: "graphql", name: "graphql-js"){
    name
    description
  }
}
```

![graphql](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql4.gif)

Bạn sẽ thấy rằng việc bạn thử đặt tên cho một field ở bên dưới `description`, IDE sẽ tự động gợi ý cho bạn những tên field có sẵn hoặc tự tạo bởi chính GraphQLAPI ! Khá hay đúng không?

![lập trình web](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql5.png)

#### **Resolvers** <a href="#resolvers" id="resolvers"></a>

Cho dù có là thư ký giỏi nhất quả đất cũng không thể đi lấy quần áo cho bạn nếu không có địa chỉ của tiệm giặt đồ.

Tương tự vậy, GraphQLserver sẽ không biết phải làm gì với query bạn đưa ra trừ khi nó biết được **resolver.**

> **Resolver** nói cho GraphQL biết nơi và cách thức để lấy data cần thiết cho field của query mà bạn yêu cầu. Sau đây là một resolver cho field \`post\` ở trên (sử dụng Apollo’s[ GraphQL-Tools](https://github.com/apollographql/graphql-tools) schema generator):

```
Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
}
```

&#x20;Ta đặt resolver ngay trong `Query` bởi vì ta muốn query cho `post` ngay lập tức. Tuy nhiên, bạn vẫn có thể dùng resolver trong sub-field, như `author` field của `post`

```
Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
},
Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  }
}
```

&#x20;Nhớ lưu ý rằng resolver sẽ không bị giới hạn bởi trong số lượng thông tin được đưa về nên bạn sẽ muốn thêm `commentsCount` cho `Post` type:

```
Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  },
  commentsCount(post) {
    return Comments.find({ postId: post.id}).count() 
  }
}
```

&#x20;Điều quan trong bạn cần hiểu ở đây là với GraphQL, **API schema của bạn và database schema sẽ bị chia ra riêng biệt**. Nói cách khác, có thể sẽ không có bất kì `author` và `commentsCount` nào trong database của mình nhưng ta vẫn có thể “mô phỏng” chúng nhờ vào resolver.

&#x20;Bạn có thể viết bất kì code gì trong resolver, vì thế mà bạn có thể dùng chúng để sửa đổi nội dung của database, vốn còn được gọi là **mutation** resolver.

Tất cả mọi thứ hay ho trên đều nhờ vào hệ thống GraphQL’s typed schema. Vì mục đích bài viết này chỉ là đơn giản giới thiệu nên tôi sẽ không có giải thích thêm cho rắc rối.

Tuy vậy, tôi khuyên bạn nên vào đọc [GraphQLdocumentation](http://graphql.org/learn/schema/) nếu như có hứng thú.

![](https://topdev.vn/blog/wp-content/uploads/2017/04/graphql6-300x27.png)
