+1

GraphQL trong Rails – Hướng dẫn tích hợp với graphql-ruby

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.

image.png

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.

image.png

✨ 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 ❤️


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.