Blog

🛠 WordPress có nên có API GraphQL trong core không?

Leonardo Losoviz
Bởi Leonardo Losoviz ·

Cập nhật 01/05/2024: Xem so sánh Gato GraphQL vs WP REST API.

WordPress 5.7 sắp ra mắt. Như đã xảy ra trong nhiều phiên bản gần đây, WP REST API cũng sẽ bổ sung thêm nhiều tính năng mới.

Trong số các tính năng mới, một tính năng đã thu hút sự chú ý của tôi: "Image Editor Accepts a List of Modifiers".

Endpoint /wp/v2/media/<id>/edit được giới thiệu trong WordPress 5.5 đi kèm với một API hạn chế chỉ chấp nhận các khai báo xoay và cắt ảnh ở cấp độ cao nhất. Trong 50124, API này đã được nâng cấp mạnh mẽ và linh hoạt hơn bằng cách chấp nhận một mảng các thay đổi thông qua tham số yêu cầu mới modifiers.

import apiFetch from '@wordpress/api-fetch';
 
const data = {
  modifiers: [
    {
      type: 'crop',
      args: {
        left  : 0,
        top   : 0,
        width : 80,
        height: 80
      }
    },
    {
      type: 'rotate',
      args: {
        angle: 90
      }
    }
  ]
};
apiFetch( { data, method: 'POST', path: '/wp/v2/media/5/edit' } );

Sự phát triển này đã mất khá nhiều thời gian để hoàn thiện.

Đầu tiên, trong WordPress 5.5, endpoint chỉnh sửa ảnh đã được giới thiệu.

Ban đầu endpoint này khá cứng nhắc, yêu cầu truyền tất cả dữ liệu cùng một lúc liên quan đến tất cả các thao tác áp dụng lên ảnh. Ví dụ, để xoay ảnh và thay đổi kích thước, chúng ta sẽ truyền dữ liệu như sau:

{
  "x": 0,
  "y": 0,
  "width": 80,
  "height": 80,
  "rotate": 90
}

Sau đó, trong WordPress 5.6, các thao tác theo lô đã được giới thiệu vào WP REST API.

Cuối cùng, trong WordPress 5.7 sắp tới, các thao tác áp dụng lên ảnh đã được tách rời, vì vậy chúng ta có các thao tác "crop""rotate". Các thao tác này có thể được thực thi riêng lẻ, nhưng cũng có thể kết hợp trong cùng một yêu cầu thông qua batching.

Như đã thấy trước đó, việc truyền dữ liệu đến endpoint giờ trông thanh lịch hơn nhiều:

{
  "modifiers": [
    {
      "type": "crop",
      "args": {
        "left"  : 0,
        "top"   : 0,
        "width" : 80,
        "height": 80
      }
    },
    {
      "type": "rotate",
      "args": {
        "angle": 90
      }
    }
  ]
}

Làm lại những gì đã có sẵn?

WP REST API không phải là API duy nhất cho WordPress. Có (ít nhất) hai lựa chọn thay thế:

  • GraphQL, thông qua WPGraphQL
  • GraphQL + persisted queries, thông qua Gato GraphQL
    (☝🏽 Đây là tôi, chủ nhà của bài viết blog này ☝🏽)

GraphQL là một loại API khá mới, vượt trội trong việc xử lý các thao tác theo lô. Nếu sử dụng GraphQL, không cần tốn thời gian và công sức để phát triển một giải pháp tùy chỉnh cho chúng, như trường hợp với REST.

Thật vậy, REST có thể được xem là đang "sao chép" tính năng này từ GraphQL.

REST sao chép GraphQL?

Việc hỗ trợ các thao tác theo lô trong WP REST API mất ít nhất 2, có thể là 3, chu kỳ phát hành để hoàn thành. Đây không phải là khoảng thời gian không đáng kể, và nó đòi hỏi sự đóng góp của nhiều người.

Nếu WordPress cũng có thể sử dụng GraphQL, và endpoint chỉnh sửa ảnh dựa trên GraphQL thay vì REST, thì các cộng tác viên này có thể làm việc trên các phát triển khác.

Liệu WordPress có tốt hơn, và được phát triển nhanh hơn nhiều, nếu có thể tận dụng những điểm mạnh nhất từ mỗi API, bất cứ khi nào thuận tiện?

Câu trả lời là của bạn...

Các thao tác theo lô trong GraphQL

Tôi sẽ chỉ cho bạn thấy không phải một, mà nhiều cách Gato GraphQL hỗ trợ các thao tác theo lô.

Cách đầu tiên là đơn giản nhất: thêm nhiều trường vào gốc của query. Ví dụ, query này đăng nhập người dùng và sau đó thêm một bình luận:

mutation LogUserInAndAddCommentToPost {
  loginUser(
    by: { credentials: { usernameOrEmail: "test", password: "pass" } }
  ) {
    id
    name
  }
  addCommentToCustomPost(
    input: {
      customPostID: 1459
      commentAs: { html: "Adding a comment: bla bla bla" }
    }
  ) {
    id
    content
    date
  }
}

(Nhân tiện, đây là client GraphiQL. Đây là hướng dẫn về cách sử dụng nó.)

Bây giờ, hai thao tác này được áp dụng trên các đối tượng khác nhau, nhưng chúng ta muốn áp dụng nhiều thao tác trên cùng một đối tượng.

Hãy làm điều đó tiếp theo: query này thêm hai bình luận vào cùng một bài viết.

mutation AddTwoCommentsToPost {
  firstComment: addCommentToCustomPost(
    input: {
      customPostID: 1459
      commentAs: { html: "This is my first response" }
    }
  ) {
    id
    content
    date
  }
  secondComment: addCommentToCustomPost(
    input: {
      customPostID: 1459
      commentAs: { html: "This is my second response" }
    }
  ) {
    id
    content
    date
  }
}

Hai bình luận này được thêm vào một bài viết đã tồn tại. Nhưng điều gì sẽ xảy ra nếu bài viết cũng cần được tạo trước?

Trong trường hợp đó, query đơn giản sẽ không còn hoạt động nữa, vì chúng ta không biết ID của bài viết chưa được tạo, thứ cần thiết làm đối số cho các thao tác khác (chú ý dấu ? trong đối số trường):

mutation CreatePostAndAddTwoCommentsToPost {
  createPost(input: { title: "Some post" }) {
    id  # <= I don't know what this value will be
  }
  addCommentToCustomPost(input: {
    customPostID: ?,
    commentAs: { html: "Blah blah blah" }
  }) {
    id
    content
    date
  }
}

Nhưng đừng lo lắng, Gato GraphQL luôn sẵn sàng hỗ trợ bạn. Nó cung cấp không phải một, mà hai giải pháp!

API GraphQL quan tâm đến bạn

Giải pháp đầu tiên là sử dụng tính năng thực thi nhiều query.

Trong query này, chúng ta thực thi thao tác đầu tiên, xuất kết quả của nó qua directive @export, và sau đó đưa giá trị này làm đầu vào cho query thứ hai:

mutation AddComment {
  addCommentToCustomPost(
    customPostID: 1459
    commentAs: { html: "Some insightful comment" }
  ) {
    id @export(as: "newCommentID")
    content
    date
  }
}
 
mutation AddResponseToComment @depends(on: "AddComment") {
  replyComment(
    parentCommentID: $newCommentID
    commentAs: { html: "Debunking your insightful comment" }
  ) {
    id
    date
    content
    parent {
      id
    }
  }
}

Thanh lịch hơn nữa, chúng ta có thể sử dụng nested mutations.

Trong query này, chúng ta thực thi thao tác đầu tiên và lồng thao tác thứ hai vào bên trong, để nó được áp dụng trên đối tượng được tạo trong thao tác đầu tiên (và sau đó lặp lại, lồng thao tác thứ 3, và cứ tiếp tục):

mutation AddCommentAndResponseAndResponse {
  addCommentToCustomPost(
    input: {
      customPostID: 1459
      commentAs: { html: "Some insightful comment" }
    }
  ) {
    id
    content
    date
    reply(input: { commentAs: { html: "Debunking your insightful comment" } }) {
      id
      date
      content
      parent {
        id
      }
      reply(input: { commentAs: { html: "No, it was right!" } }) {
        id
        date
        content
        parent {
          id
        }
      }
    }
  }
}

Như một phần thưởng, các thao tác theo lô có thể được áp dụng không chỉ trên một thực thể đơn lẻ, mà trên nhiều thực thể cùng một lúc, trong cùng một yêu cầu.

Trong query này, các bình luận mới và tất cả các phản hồi của chúng đang được thêm vào nhiều bài viết:

mutation AddCommentAndResponseToManyPosts {
  posts(ids: [1657, 1153, 1499, 1459]) {
    id
    addComment(input: { commentAs: { html: "Some insightful comment" } }) {
      id
      content
      date
      reply(
        input: { commentAs: { html: "Debunking your insightful comment" } }
      ) {
        id
        date
        content
        parent {
          id
        }
      }
    }
  }
}

Và plugin còn có thêm một chiêu nữa: bằng cách sử dụng tính năng embeddable fields, chúng ta có thể tùy chỉnh nội dung được truyền vào mỗi đối số trường, sử dụng dữ liệu từ chính đối tượng đó!

Trong query này, các bình luận chứa thông tin từ đối tượng mà chúng đang được tạo trên đó:

mutation AddCustomCommentAndResponseToManyPosts {
  posts(ids: [1657, 1153, 1499, 1459]) {
    id
    addComment(
      input: {
        commentAs: { html: "The post has ID {{ id }} and title {{ title }}" }
      }
    ) {
      id
      content
      date
      reply(
        input: {
          commentAs: {
            html: "The parent comment was posted on {{ dateStr(format: \"d/m/Y\") }}. Cool, right?"
          }
        }
      ) {
        id
        date
        content
        parent {
          id
        }
      }
    }
  }
}

Tận dụng tốt nhất từ REST và GraphQL khi thuận tiện

Khi Full Site Editing được phát triển và mở rộng, WordPress sẽ ngày càng phụ thuộc nhiều hơn vào các API của mình.

Về các tính năng hiện có, REST API cho đến nay đã hoạt động rất tốt. Không có lý do gì để xây dựng lại những gì không bị hỏng.

Tuy nhiên, đối với các tính năng mới chưa được phát triển, liệu WordPress có được hưởng lợi từ việc sử dụng REST hoặc GraphQL, tùy thuộc vào cái nào thuận tiện hơn cho tính năng cụ thể đó?

Câu trả lời là của bạn...

Ý kiến của bạn là gì?


Đăng ký nhận bản tin của chúng tôi

Cập nhật tất cả những điều mới từ Gato GraphQL.