Lặp Lại và Thao Tác Giá Trị Trường
Bổ sung các meta directive vào schema GraphQL, để lặp lại và thao tác các phần tử giá trị của các trường mảng và đối tượng:
@underArrayItem@underJSONObjectProperty@underEachArrayItem@underEachJSONObjectProperty@objectClone
@underArrayItem
@underArrayItem làm cho directive lồng nhau được áp dụng trên một phần tử cụ thể từ mảng.
Trong query dưới đây, chỉ có phần tử đầu tiên trong mảng chứa tên danh mục được chuyển đổi thành chữ hoa:
query {
posts {
categoryNames
@underArrayItem(index: 0)
@strUpperCase
}
}...cho kết quả:
{
"data": {
"posts": {
"categoryNames": [
"NEWS",
"sports"
]
}
}
}@underJSONObjectProperty
@underJSONObjectProperty làm cho directive lồng nhau nhận một mục từ đối tượng JSON được truy vấn.
Directive này đặc biệt hữu ích để trích xuất và thao tác một phần dữ liệu mong muốn sau khi truy vấn API bên ngoài, thứ thường sẽ có kiểu JSONObject chung (như khi sử dụng function field _sendJSONObjectItemHTTPRequest từ extension HTTP Client).
Trong query dưới đây, chúng ta lấy một đối tượng JSON từ WP REST API, và sử dụng @underJSONObjectProperty để thao tác thuộc tính type của phản hồi, chuyển đổi nó thành chữ hoa:
query {
postData: _sendJSONObjectItemHTTPRequest(input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
})
@underJSONObjectProperty(by: { key: "type" })
@strUpperCase
}Kết quả sẽ là:
{
"data": {
"postData": {
"id": 1,
"date": "2019-08-02T07:53:57",
"type": "POST",
"title": {
"rendered": "Hello world!"
}
}
}
}Ngoài việc nhận "key" để trỏ đến một thuộc tính nằm ở cấp đầu tiên của đối tượng JSON, directive này cũng có thể nhận "path" để điều hướng trong cấu trúc nội tại của đối tượng, sử dụng . làm dấu phân cách giữa các cấp.
Trong query dưới đây, endpoint WP REST API cho một bài viết cung cấp thuộc tính "title.rendered". Chúng ta có thể điều hướng đến phần tử con thực tế đó, và chuyển đổi nó thành dạng tiêu đề:
query {
postData: _sendJSONObjectItemHTTPRequest(input: {
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/1/?_fields=id,type,title,date"
})
@underJSONObjectProperty(by: { path: "title.rendered" })
@strTitleCase
}Kết quả sẽ là:
{
"data": {
"postData": {
"id": 1,
"date": "2019-08-02T07:53:57",
"type": "post",
"title": {
"rendered": "HELLO WORLD!"
}
}
}
}@underEachArrayItem
@underEachArrayItem lặp qua các phần tử mảng từ một trường nào đó trong entity được truy vấn, và thực thi (các) directive lồng nhau trên từng phần tử.
Ví dụ, trường Post.categoryNames có kiểu [String]. Sử dụng @underEachArrayItem, chúng ta có thể lặp qua tên danh mục và áp dụng directive @strTranslate cho chúng.
Trong query này, danh mục bài viết được dịch từ tiếng Anh sang tiếng Pháp:
query {
posts {
id
title
categoryNames
@underEachArrayItem
@strTranslate(
from: "en",
to: "fr"
)
}
}...cho kết quả:
{
"data": {
"posts": [
{
"id": 662,
"title": "Explaining the privacy policy",
"categoryNames": [
"Non classé"
]
},
{
"id": 28,
"title": "HTTP caching improves performance",
"categoryNames": [
"Avancé"
]
},
{
"id": 25,
"title": "Public or Private API mode, for extra security",
"categoryNames": [
"Ressource",
"Blog",
"Avancé"
]
}
]
}
}@underEachArrayItem có thể truyền cả chỉ số và giá trị của phần tử đang được lặp như một biến động cho (các) directive lồng nhau, thông qua directive args passIndexOnwardsAs và passValueOnwardsAs.
Query này minh họa việc sử dụng các biến động $index và $value:
{
_echo(value: ["first", "second", "third"])
@underEachArrayItem(
passIndexOnwardsAs: "index"
passValueOnwardsAs: "value"
)
@applyField(
name: "_echo"
arguments: {
value: {
index: $index,
value: $value
}
},
setResultInResponse: true
)
}Kết quả là:
{
"data": {
"_echo": [
{
"index": 0,
"value": "first"
},
{
"index": 1,
"value": "second"
},
{
"index": 2,
"value": "third"
}
]
}
}@underEachArrayItem cũng có thể giới hạn các vị trí của mảng để lặp, thông qua param filter->by, có thể chấp nhận mục include hoặc exclude.
Query này:
{
including: _echo([
"first",
"second",
"third"
])
@underEachArrayItem(
filter: {
by: {
include: [0, 2]
}
}
)
@strUpperCase
excluding: _echo([
"first",
"second",
"third"
])
@underEachArrayItem(
filter: {
by: {
exclude: [0, 2]
}
}
)
@strUpperCase
}...cho kết quả:
{
"data": {
"including": [
"FIRST",
"second",
"THIRD"
],
"excluding": [
"first",
"SECOND",
"third"
]
}
}@underEachJSONObjectProperty
@underEachJSONObjectProperty tương tự như @underEachArrayItem, nhưng hoạt động trên các phần tử JSONObject.
Trong query này, chúng ta lặp qua tất cả các mục trong đối tượng JSON và thay thế bất kỳ mục null nào bằng chuỗi rỗng:
{
_echo(
value: {
first: "hello",
second: "world",
third: null
}
)
@underEachJSONObjectProperty
@default(value: "")
}...cho kết quả:
{
"data": {
"_echo": {
"first": "hello",
"second": "world",
"third": ""
}
}
}@underEachJSONObjectProperty có thể truyền khóa và giá trị mà nó đang lặp như một biến động cho (các) directive lồng nhau, thông qua directive args passKeyOnwardsAs và passValueOnwardsAs.
Query này minh họa việc sử dụng các biến động $key và $value:
{
_echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
passKeyOnwardsAs: "key"
passValueOnwardsAs: "value"
)
@applyField(
name: "_echo"
arguments: {
value: {
key: $key,
value: $value
}
},
setResultInResponse: true
)
}Kết quả là:
{
"data": {
"_echo": {
"uno": {
"key": "uno",
"value": "first"
},
"dos": {
"key": "dos",
"value": "second"
},
"tres": {
"key": "tres",
"value": "third"
}
}
}
}@underEachJSONObjectProperty cũng có thể giới hạn các khóa từ đối tượng JSON để lặp, thông qua param filter->by, có thể chấp nhận mục includeKeys hoặc excludeKeys.
Query này:
{
includingKeys: _echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
filter: {
by: {
includeKeys: ["uno", "tres"]
}
}
)
@strUpperCase
excludingKeys: _echo(value: {
uno: "first",
dos: "second",
tres: "third"
})
@underEachJSONObjectProperty(
filter: {
by: {
excludeKeys: ["uno", "tres"]
}
}
)
@strUpperCase
}...cho kết quả:
{
"data": {
"includingKeys": {
"uno": "FIRST",
"dos": "second",
"tres": "THIRD"
},
"excludingKeys": {
"uno": "first",
"dos": "SECOND",
"tres": "third"
}
}
}@objectClone
Các đối tượng JSON có thể được truy cập theo tham chiếu trong các field resolver (chứ không phải bằng cách sao chép/nhân bản đối tượng). Khi đó, khi đối tượng JSON bị sửa đổi, sự sửa đổi này sẽ hiển thị cho tất cả các trường truy xuất đối tượng JSON này.
Đây là trường hợp của trường Block.attributes:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
attributes
}
}
}...cho kết quả:
{
"data": {
"posts": [
{
"blocks": [
{
"attributes": {
"content": "Image Block (Full width)",
"level": 2
}
},
{
"attributes": {
"content": "Gallery Block",
"level": 2
}
}
]
}
]
}
}Trong query dưới đây, trong khi originalAttributes chỉ đơn giản là truy xuất các thuộc tính, transformedAttributes cũng sẽ dịch thuộc tính content sang tiếng Pháp:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
originalAttributes: attributes
transformedAttributes: attributes
@underJSONObjectProperty(by: { key: "content" })
@strTranslate(to: "fr")
}
}
}Tuy nhiên, vì entity Block được truy vấn tham chiếu đến cùng một đối tượng JSON trên cả originalAttributes và transformedAttributes, các phép biến đổi được thực hiện bởi trường sau cũng sẽ ảnh hưởng đến trường trước (điều này không phụ thuộc vào thứ tự xuất hiện của chúng trong query).
Kết quả là, cả hai trường đều được dịch sang tiếng Pháp:
{
"data": {
"posts": [
{
"blocks": [
{
"originalAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
},
"transformedAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
}
},
{
"originalAttributes": {
"content": "Bloc Galerie",
"level": 2
},
"transformedAttributes": {
"content": "Bloc Galerie",
"level": 2
}
}
]
}
]
}
}Chúng ta có thể tránh vấn đề này bằng cách thêm directive @objectClone trên trường transformedAttributes, để các sửa đổi được thực hiện trên một đối tượng JSON được nhân bản:
{
posts {
blocks(filterBy: { include: "core/heading" } ) {
originalAttributes: attributes
transformedAttributes: attributes
@objectClone
@underJSONObjectProperty(by: { key: "content" })
@strTranslate(to: "fr")
}
}
}...cho kết quả:
{
"data": {
"posts": [
{
"blocks": [
{
"originalAttributes": {
"content": "Image Block (Full width)",
"level": 2
},
"transformedAttributes": {
"content": "Bloc d'image (pleine largeur)",
"level": 2
}
},
{
"originalAttributes": {
"content": "Gallery Block",
"level": 2
},
"transformedAttributes": {
"content": "Bloc Galerie",
"level": 2
}
}
]
}
]
}
}Ví dụ thêm
Trong query này, @underEachArrayItem bao bọc @underJSONObjectProperty, bản thân nó bao bọc @strUpperCase, chuyển đổi thuộc tính "title.rendered" thành chữ hoa, cho nhiều mục bài viết được lấy qua WP REST API:
query {
postListData: _sendJSONObjectCollectionHTTPRequest(
url: "https://newapi.getpop.org/wp-json/wp/v2/posts/?per_page=3&_fields=id,type,title,date"
)
@underEachArrayItem
@underJSONObjectProperty(by: { path: "title.rendered" })
@strUpperCase
}...cho kết quả:
{
"data": {
"postListData": [
{
"id": 1692,
"date": "2022-04-26T10:10:08",
"type": "post",
"title": {
"rendered": "MY BLOGROLL"
}
},
{
"id": 1657,
"date": "2020-12-21T08:24:18",
"type": "post",
"title": {
"rendered": "A TALE OF TWO CITIES – TEASER"
}
},
{
"id": 1499,
"date": "2019-08-08T02:49:36",
"type": "post",
"title": {
"rendered": "COPE WITH WORDPRESS: POST DEMO CONTAINING PLENTY OF BLOCKS"
}
}
]
}
}