Tài nguyên
Tài nguyênCác best practice trong GraphQL

Các best practice trong GraphQL

GraphQL đã đủ trưởng thành và tồn tại đủ lâu để cộng đồng xuất bản nhiều bài viết chia sẻ các best practice. Những hướng dẫn này bao gồm hầu hết mọi khía cạnh của GraphQL, bao gồm thiết kế schema, quy ước đặt tên, xử lý bảo mật và cung cấp thông báo lỗi có ý nghĩa, cùng nhiều chủ đề khác.

Đây là một số hướng dẫn thuyết phục nhất về các best practice trong GraphQL.

Best practice trên graphql.org

Trang web chính thức của GraphQL cung cấp phần giới thiệu tổng quát về các best practice trong GraphQL.

Những điểm này chủ yếu bao gồm các vấn đề cấp cao, chẳng hạn như:

Vị trí của lớp GraphQL trong kiến trúc

Những khuyến nghị của Lee Byron

Không lâu sau khi ra mắt GraphQL với thế giới, người tạo ra GraphQL — Lee Byron — đã xuất bản bài viết Lessons From 4 Years of GraphQL, mô tả cách chúng ta nên tiếp cận làm việc với GraphQL về mặt khái niệm:

  • Đặt tên rất quan trọng
  • Hãy nghĩ theo đồ thị, không phải theo endpoint
  • Mô tả dữ liệu, không phải giao diện hiển thị
  • GraphQL là một giao diện mỏng
  • Che giấu các chi tiết triển khai

Ông cũng trình bày chi tiết nhiều nguyên tắc và bài học quý giá mà ông đúc kết được khi sử dụng GraphQL tại Facebook.

GraphQL Rules

GraphQL Rules là một trang web được tạo ra đặc biệt để trình bày các best practice hàng ngày khi làm việc với GraphQL, chủ yếu liên quan đến việc thiết kế schema GraphQL.

Tài nguyên này rất toàn diện. Nó tổng hợp thông tin từ một số tài nguyên xuất sắc (chẳng hạn như bài viết Designing GraphQL Mutations và hướng dẫn của Shopify Designing a GraphQL API) và trình bày tất cả một cách súc tích.

Các quy tắc được mô tả bao gồm:

  1. Quy tắc đặt tên
    • Dùng camelCase cho các trường và đối số GraphQL.
    • Dùng UpperCamelCase cho các kiểu GraphQL.
    • Dùng CAPITALIZED_WITH_UNDERSCORES để đặt tên cho các kiểu ENUM.
  2. Quy tắc về kiểu dữ liệu
    • Dùng kiểu scalar tùy chỉnh nếu muốn khai báo các trường hoặc đối số với giá trị ngữ nghĩa cụ thể.
    • Dùng Enum cho các trường chứa một tập hợp giá trị cụ thể.
  3. Quy tắc về trường (Output)
    • Dùng tên ngữ nghĩa cho các trường và tránh để lộ chi tiết triển khai trong tên trường.
    • Dùng trường Non-Null nếu trường đó luôn có giá trị.
    • Nhóm càng nhiều trường liên quan vào một Object type tùy chỉnh càng tốt.
  4. Quy tắc về đối số (Input)
    • Nhóm các đối số liên quan vào một input-type mới.
    • Dùng kiểu scalar chặt chẽ cho đối số, ví dụ DateTime thay vì String.
    • Đánh dấu các đối số là required nếu chúng cần thiết để thực thi queries.
  5. Quy tắc về danh sách
    • Để lọc danh sách, dùng đối số filter chứa tất cả các bộ lọc có sẵn.
    • Dùng đối số sort kiểu Enum hoặc [Enum!] để sắp xếp danh sách.
    • Dùng limit với giá trị mặc định và skip để giới hạn số phần tử trả về trong danh sách.
    • Dùng đối số page, perPage cho phân trang và trả về kiểu output với items (mảng phần tử) và pageInfo (siêu dữ liệu).
    • Đối với danh sách vô hạn (cuộn vô hạn), dùng Relay Cursor Connections Specification.
  6. Quy tắc về mutation
    • Dùng Namespace-types để nhóm các mutation trong một tài nguyên duy nhất.
    • Vượt ra ngoài CRUD — tạo các mutation nhỏ cho các thao tác nghiệp vụ khác nhau trên tài nguyên.
    • Cân nhắc khả năng thực hiện mutation trên nhiều mục (thay đổi hàng loạt cùng kiểu).
    • Các mutation phải mô tả rõ ràng tất cả các đối số bắt buộc, không được có các tùy chọn mơ hồ.
    • Trong mutation, đặt tất cả biến vào một đối số input duy nhất.
    • Mỗi mutation phải có một payload type duy nhất.

Best practice cho resolver

Bài viết GraphQL Resolvers: Best Practices mô tả cách tạo field resolver tốt nhất. Mặc dù bài viết hướng đến các server Node.js (cơ sở hạ tầng của PayPal dựa trên Express), nhiều bài học trong đó cũng có thể áp dụng cho các công nghệ khác, kể cả PHP.

Những điểm rút ra chính là:

  • Việc lấy và truyền dữ liệu từ cha sang con nên được sử dụng tiết kiệm.
  • Dùng các thư viện như dataloader để loại bỏ các yêu cầu downstream trùng lặp.
  • Lưu ý đến áp lực mà bạn đang tạo ra trên các nguồn dữ liệu.
  • Không biến đổi "context". Đảm bảo code nhất quán và ít lỗi hơn.
  • Viết resolver dễ đọc, dễ bảo trì, dễ kiểm thử. Không quá khéo léo.
  • Làm cho resolver của bạn càng mỏng càng tốt. Trích xuất logic lấy dữ liệu thành các hàm async có thể tái sử dụng.

OWASP - GraphQL Cheat Sheet

OWASP (Open Web Application Security Project) là một tổ chức phi lợi nhuận hoạt động để cải thiện bảo mật phần mềm. Tổ chức này nghiên cứu về cách các công nghệ khác nhau dễ bị khai thác, và mô tả chi tiết các giải pháp cho các vấn đề bảo mật, giúp các nhà phát triển phòng ngừa tấn công dễ dàng hơn.

OWASP đã xuất bản GraphQL Cheat Sheet, giải thích những cuộc tấn công phổ biến nhất và các vấn đề bảo mật lớn nhất trong GraphQL, cũng như cách xử lý chúng.

Các cuộc tấn công phổ biến vào GraphQL là:

  1. Injection - thường bao gồm nhưng không giới hạn ở:
    • SQL và NoSQL injection
    • OS Command injection
    • SSRF và CRLF injection/Request Smuggling
  2. DoS (Denial of Service)
  3. Lạm dụng phân quyền không đúng: truy cập không phù hợp hoặc quá mức, bao gồm IDOR
  4. Batching Attacks, một phương thức tấn công brute force đặc thù của GraphQL
  5. Lạm dụng các cấu hình mặc định không an toàn

OWASP sau đó cung cấp các khuyến nghị về cách tránh từng loại tấn công trên.

Best practice với GraphQL queries

Nhóm Apollo đã xuất bản GraphQL query best practices, cung cấp những hiểu biết thực tế về cách soạn thảo queries GraphQL.

Ví dụ, hai queries sau đây đạt được cùng một mục tiêu, nhưng vì queries đầu tiên có tên thao tác nên nó dễ hiểu hơn và hữu ích hơn khi debug:

# Khuyến nghị ✅
query GetBooks {
  books {
    title
  }
}
 
# Không khuyến nghị ❌
query {
  books {
    title
  }
}

Các gợi ý của họ bao gồm:

  • Đặt tên cho tất cả các thao tác
  • Dùng biến để cung cấp đối số GraphQL
  • Chỉ truy vấn dữ liệu bạn cần, ở nơi bạn cần
  • Dùng fragment để đóng gói các tập hợp trường liên quan
  • Truy vấn dữ liệu toàn cục và dữ liệu riêng của người dùng một cách tách biệt

Tận dụng one graph

Cũng từ nhóm Apollo là trang web Principled GraphQL giải thích rằng GraphQL không chỉ là một đặc tả mà, có lẽ quan trọng hơn, là một giao diện để tương tác với "đồ thị" dữ liệu của công ty chúng ta.

Thông qua danh sách 10 nguyên tắc, trang web này mô tả cách khai thác tối đa đồ thị duy nhất:

  1. One Graph: Công ty của bạn nên có một đồ thị thống nhất, thay vì nhiều đồ thị do mỗi nhóm tạo ra.
  2. Federated Implementation: Mặc dù chỉ có một đồ thị, việc triển khai đồ thị đó nên được phân phối giữa nhiều nhóm.
  3. Track the Schema in a Registry: Nên có một nguồn sự thật duy nhất để đăng ký và theo dõi đồ thị.
  4. Abstract, Demand-Oriented Schema: Schema nên hoạt động như một lớp trừu tượng cung cấp tính linh hoạt cho người dùng trong khi ẩn đi các chi tiết triển khai dịch vụ.
  5. Use an Agile Approach to Schema Development: Schema nên được xây dựng tăng dần dựa trên các yêu cầu thực tế và phát triển mượt mà theo thời gian.
  6. Iteratively Improve Performance: Quản lý hiệu suất nên là một quá trình liên tục, dựa trên dữ liệu, thích nghi dần dần với các tải queries và triển khai dịch vụ thay đổi.
  7. Use Graph Metadata to Empower Developers: Các nhà phát triển nên được trang bị nhận thức phong phú về đồ thị trong suốt quá trình phát triển.
  8. Access and Demand Control: Cấp quyền truy cập vào đồ thị trên cơ sở từng client, và quản lý những gì và cách client có thể truy cập nó.
  9. Structured Logging: Ghi lại nhật ký có cấu trúc của tất cả các thao tác đồ thị và tận dụng chúng làm công cụ chính để hiểu cách sử dụng đồ thị.
  10. Separate the GraphQL Layer from the Service Layer: Áp dụng kiến trúc phân lớp với chức năng đồ thị được tách thành một tầng riêng biệt thay vì tích hợp vào mỗi dịch vụ.