Nếu bạn đang xây dựng một ứng dụng có frontend phức tạp, và đã quá mệt mỏi với việc phải tạo quá nhiều endpoint REST chỉ để phục vụ từng giao diện frontend. Đây là lúc bạn có thể tìm đến GraphQL.
GraphQL không phải là một công nghệ "mới nổi" nữa — nó đã và đang được hàng loạt công ty lớn như GitHub, Shopify, và Twitter sử dụng để xây dựng các API mạnh mẽ, linh hoạt, dễ mở rộng.
1. GraphQL là gì?
GraphQL là một ngôn ngữ truy vấn dữ liệu (query language) dành cho API, được phát triển bởi Facebook vào năm 2012 và công bố ra cộng đồng năm 2015.
Nhưng đừng nhầm: GraphQL không phải là cơ sở dữ liệu, cũng không phải là framework backend 👉 GraphQL là một cách mới để thiết kế và giao tiếp với API, thay thế cho mô hình REST truyền thống.
2. REST vs GraphQL: Tư duy khác biệt
Với REST:
- API được chia nhỏ thành nhiều endpoint cố định (ví dụ: /posts, /posts/1/comments, /users/1)
- Mỗi endpoint thường trả về một cấu trúc dữ liệu cố định
- Nếu frontend cần ít hơn hoặc nhiều hơn dữ liệu đó, thì… không còn cách nào ngoài việc sửa backend.
Với GraphQL:
- Chỉ có một endpoint duy nhất (/graphql)
- Client gửi một truy vấn mô tả chính xác cấu trúc dữ liệu mà họ muốn
- Server chỉ trả về đúng dữ liệu đó – không thừa, không thiếu.
✨ Hệ quả:
- Giảm số lượng request cần thiết
- Giảm bandwidth (ít dữ liệu dư thừa)
- Dễ thay đổi UI phía frontend mà không phải sửa API
3. Cấu trúc cơ bản của GraphQL
Schema: Định nghĩa các kiểu dữ liệu (type) mà API hỗ trợ, các truy vấn (query) và thao tác (mutation) mà client có thể gọi.
Type System: GraphQL sử dụng hệ thống kiểu tĩnh để mô tả dữ liệu. Mỗi type giống như một “giao diện hợp đồng” giữa frontend và backend.
Ví dụ:
type Post { id: ID! title: String! content: String
}
Query: Truy vấn dữ liệu, giống như GET trong REST.
Ví dụ:
query { posts { id title }
}
Mutation: Thực hiện thay đổi dữ liệu – tương đương với POST, PUT, DELETE trong REST.
Resolver: Mỗi field trong schema có một "resolver" – là hàm backend chịu trách nhiệm trả về dữ liệu tương ứng. Trong Rails, bạn sẽ viết logic này trong các method Ruby.
4. Tại sao nên sử dụng GraphQL cho Rails (hoặc bất kỳ backend nào)?
- Rails được thiết kế để phục vụ frontend nhanh chóng, và GraphQL giảm rất nhiều logic viết tay cho API.
- Rails cũng là nơi dễ tổ chức schema, resolver, model vì MVC rõ ràng.
- Khi kết hợp với frontend hiện đại (React, Vue, mobile), GraphQL giúp dev frontend phát triển nhanh hơn, chủ động hơn, không bị "chờ backend thêm field".
Khi bạn dùng GraphQL, bạn thiết kế schema như thiết kế UI cho dev frontend – mọi truy vấn đều rõ ràng, có thể đoán trước, có tài liệu tự động. Không còn là "anh backend thêm dùm cái field avatar_url", vì frontend tự chọn field nào họ muốn dùng.
5. Ví dụ sử dụng GraphQL trong Rails
Giả sử bạn đang xây dựng một ứng dụng blog nhỏ – nơi có bài viết (Post) với title và content. Chúng ta sẽ:
- Tạo model Post trong Rails
- Tạo type GraphQL tương ứng
- Viết Query để lấy danh sách bài viết
- Viết Mutation để thêm bài viết mới
- Kiểm tra truy vấn thực tế qua GraphiQL hoặc Postman
5.1 Tạo model Post
Chạy lệnh này trong terminal để tạo bảng và model Post:
rails generate model Post title:string content:text
rails db:migrate
Seed thử vài bài viết để có dữ liệu test:
# db/seeds.rb
Post.create!(title: "Chào GraphQL", content: "Đây là bài viết đầu tiên!")
Post.create!(title: "GraphQL vs REST", content: "Cùng tìm hiểu sự khác nhau!")
rails db:seed
5.2 Cài đặt GraphQL và scaffold
Nếu chưa cài, bạn thêm vào Gemfile:
gem 'graphql'
Chạy lệnh:
bundle install
rails generate graphql:install
Lệnh này sẽ:
- Tạo thư mục app/graphql/
- Tạo file schema (your_app_schema.rb)
- Tạo controller GraphqlController
- Thêm route /graphql
5.3 Tạo GraphQL Type cho Post
Tạo file app/graphql/types/post_type.rb:
module Types class PostType < Types::BaseObject field :id, ID, null: false field :title, String, null: false field :content, String, null: true end
end
5.4 Thêm Query để lấy danh sách bài viết
Mở app/graphql/types/query_type.rb và thêm:
module Types class QueryType < Types::BaseObject # Truy vấn tất cả bài viết field :posts, [PostType], null: false def posts Post.all end # Truy vấn bài viết theo id field :post, PostType, null: true do argument :id, ID, required: true end def post(id:) Post.find_by(id: id) end end
end
5.5 Thực hiện truy vấn GraphQL
Mở trình duyệt đến http://localhost:3000/graphiql (Nếu bạn không dùng --api khi tạo app thì GraphiQL sẽ khả dụng) Thử truy vấn:
query { posts { id title }
}
Truy vấn theo ID:
query { post(id: 1) { title content }
}
5.6 Tạo Mutation để thêm bài viết mới
Chạy lệnh tạo mutation:
rails generate graphql:mutation CreatePost
Chỉnh file app/graphql/mutations/create_post.rb:
module Mutations class CreatePost < BaseMutation argument :title, String, required: true argument :content, String, required: false type Types::PostType def resolve(title:, content: nil) Post.create!(title: title, content: content) end end
end
Sau đó, đăng ký mutation này trong mutation_type.rb:
module Types class MutationType < Types::BaseObject field :create_post, mutation: Mutations::CreatePost end
end
5.7 Thử mutation trong GraphiQL
mutation { createPost(input: { title: "Bài mới", content: "Viết bằng GraphQL" }) { id title content }
}
Kết quả sẽ trả về bài viết vừa tạo.
* Giải thích từng phần:
Thành phần | Mục đích |
---|---|
PostType | Định nghĩa cấu trúc dữ liệu trả về |
QueryType | Nơi khai báo các truy vấn được phép gọi |
Mutation | Định nghĩa thao tác ghi (viết, sửa, xoá) |
resolve | Chính là “controller logic” – nơi xử lý dữ liệu |
Tổng kết
Đến đây, bạn đã:
- Cài đặt thành công GraphQL cho ứng dụng Rails
- Tạo được truy vấn (Query) để lấy dữ liệu
- Tạo mutation để thêm mới bài viết
- Thử nghiệm với giao diện GraphiQL
Ở bài viết tiếp theo, chúng ta sẽ tìm hiểu sâu hơn về:
- Thêm authentication vào mutation (yêu cầu user đăng nhập)
- Triển khai pagination
- Lồng nested query (ví dụ bài viết kèm bình luận)
- Tối ưu performance với caching
Cảm ơn các bạn đã đọc