쿼리 함수
쿼리 함수필드 값 반복 및 조작

필드 값 반복 및 조작

Included in the “Power Extensions” bundle

array 및 object 필드의 값 요소를 반복하고 조작하기 위한 메타 디렉티브를 GraphQL 스키마에 추가합니다:

  1. @underArrayItem
  2. @underJSONObjectProperty
  3. @underEachArrayItem
  4. @underEachJSONObjectProperty
  5. @objectClone

@underArrayItem

@underArrayItem은 중첩된 디렉티브를 배열의 특정 항목에 적용합니다.

아래 쿼리에서는 카테고리 이름 배열의 첫 번째 항목만 대문자로 변환됩니다:

query {
  posts {
    categoryNames
      @underArrayItem(index: 0)
        @strUpperCase
  }
}

...결과:

{
  "data": {
    "posts": {
      "categoryNames": [
        "NEWS",
        "sports"
      ]
    }
  }
}

@underJSONObjectProperty

@underJSONObjectProperty는 중첩된 디렉티브가 쿼리된 JSON 객체의 항목을 받을 수 있도록 합니다.

이 디렉티브는 외부 API를 쿼리한 후 원하는 데이터를 추출하고 조작하는 데 특히 유용합니다. 외부 API는 대체로 일반적인 JSONObject 타입을 가지고 있으며(HTTP Client 익스텐션의 함수 필드 _sendJSONObjectItemHTTPRequest를 사용할 때가 그 예입니다).

아래 쿼리에서는 WP REST API에서 가져온 JSON 객체를 사용하며, @underJSONObjectProperty를 이용해 응답의 type 속성을 조작하여 대문자로 변환합니다:

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
}

이렇게 하면 다음이 생성됩니다:

{
  "data": {
    "postData": {
      "id": 1,
      "date": "2019-08-02T07:53:57",
      "type": "POST",
      "title": {
        "rendered": "Hello world!"
      }
    }
  }
}

JSON 객체의 첫 번째 레벨에 있는 속성을 가리키는 "key"를 받는 것 외에도, 이 디렉티브는 객체의 내부 구조를 탐색하기 위한 "path"도 받을 수 있으며, 레벨 간 구분자로 .을 사용합니다.

아래 쿼리에서 포스트에 대한 WP REST API 엔드포인트는 "title.rendered" 속성을 제공합니다. 해당 하위 요소로 탐색하여 타이틀 케이스로 변환할 수 있습니다:

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
}

이렇게 하면 다음이 생성됩니다:

{
  "data": {
    "postData": {
      "id": 1,
      "date": "2019-08-02T07:53:57",
      "type": "post",
      "title": {
        "rendered": "HELLO WORLD!"
      }
    }
  }
}

@underEachArrayItem

@underEachArrayItem은 쿼리된 엔티티의 특정 필드에 있는 배열 항목을 반복하며, 각 항목에 대해 중첩된 디렉티브를 실행합니다.

예를 들어, 필드 Post.categoryNames[String] 타입입니다. @underEachArrayItem을 사용하면 카테고리 이름을 반복하며 @strTranslate 디렉티브를 적용할 수 있습니다.

이 쿼리에서는 포스트 카테고리가 영어에서 프랑스어로 번역됩니다:

query {
  posts {
    id
    title
    categoryNames
      @underEachArrayItem
        @strTranslate(
          from: "en",
          to: "fr"
        )
  }
}

...결과:

{
  "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은 디렉티브 인수 passIndexOnwardsAspassValueOnwardsAs를 통해 반복 중인 요소의 인덱스와 값을 동적 변수로 중첩된 디렉티브에 전달할 수 있습니다.

이 쿼리는 동적 변수 $index$value의 사용법을 보여줍니다:

{
  _echo(value: ["first", "second", "third"])
    @underEachArrayItem(
      passIndexOnwardsAs: "index"
      passValueOnwardsAs: "value"
    )
      @applyField(
        name: "_echo"
        arguments: {
          value: {
            index: $index,
            value: $value
          }
        },
        setResultInResponse: true
      )
}

결과는 다음과 같습니다:

{
  "data": {
    "_echo": [
      {
        "index": 0,
        "value": "first"
      },
      {
        "index": 1,
        "value": "second"
      },
      {
        "index": 2,
        "value": "third"
      }
    ]
  }
}

@underEachArrayItem은 또한 파라미터 filter->by를 통해 반복할 배열의 위치를 제한할 수 있으며, include 또는 exclude 항목을 받을 수 있습니다.

이 쿼리:

{
  including: _echo([
    "first",
    "second",
    "third"
  ])
    @underEachArrayItem(
      filter: {
        by: {
          include: [0, 2]
        }
      }
    )
      @strUpperCase
 
  excluding: _echo([
    "first",
    "second",
    "third"
  ])
    @underEachArrayItem(
      filter: {
        by: {
          exclude: [0, 2]
        }
      }
    )
      @strUpperCase
}

...결과:

{
  "data": {
    "including": [
      "FIRST",
      "second",
      "THIRD"
    ],
    "excluding": [
      "first",
      "SECOND",
      "third"
    ]
  }
}

@underEachJSONObjectProperty

@underEachJSONObjectProperty@underEachArrayItem과 유사하지만, JSONObject 요소에 대해 동작합니다.

이 쿼리에서는 JSON 객체의 모든 항목을 반복하며 null 항목을 빈 문자열로 대체합니다:

{
  _echo(
    value: {
      first: "hello",
      second: "world",
      third: null
    }
  )
    @underEachJSONObjectProperty
      @default(value: "")
}

...결과:

{
  "data": {
    "_echo": {
      "first": "hello",
      "second": "world",
      "third": ""
    }
  }
}

@underEachJSONObjectProperty는 디렉티브 인수 passKeyOnwardsAspassValueOnwardsAs를 통해 반복 중인 키와 값을 동적 변수로 중첩된 디렉티브에 전달할 수 있습니다.

이 쿼리는 동적 변수 $key$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
      )
}

결과는 다음과 같습니다:

{
  "data": {
    "_echo": {
      "uno": {
        "key": "uno",
        "value": "first"
      },
      "dos": {
        "key": "dos",
        "value": "second"
      },
      "tres": {
        "key": "tres",
        "value": "third"
      }
    }
  }
}

@underEachJSONObjectProperty는 또한 파라미터 filter->by를 통해 반복할 JSON 객체의 키를 제한할 수 있으며, includeKeys 또는 excludeKeys 항목을 받을 수 있습니다.

이 쿼리:

{
  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
}

...결과:

{
  "data": {
    "includingKeys": {
      "uno": "FIRST",
      "dos": "second",
      "tres": "THIRD"
    },
    "excludingKeys": {
      "uno": "first",
      "dos": "SECOND",
      "tres": "third"
    }
  }
}

@objectClone

JSON 객체는 필드 리졸버에서 복사/복제 없이 참조로 접근될 수 있습니다. 그 경우, JSON 객체가 수정되면 해당 JSON 객체를 조회하는 모든 필드에 수정 사항이 반영됩니다.

이것은 필드 Block.attributes의 경우에 해당합니다:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      attributes
    }
  }
}

...결과:

{
  "data": {
    "posts": [
      {
        "blocks": [
          {
            "attributes": {
              "content": "Image Block (Full width)",
              "level": 2
            }
          },
          {
            "attributes": {
              "content": "Gallery Block",
              "level": 2
            }
          }
        ]
      }
    ]
  }
}

아래 쿼리에서 originalAttributes는 단순히 속성을 가져오는 반면, transformedAttributescontent 속성을 프랑스어로 번역합니다:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      originalAttributes: attributes
      transformedAttributes: attributes
        @underJSONObjectProperty(by: { key: "content" })
          @strTranslate(to: "fr")
    }
  }
}

그러나 쿼리된 Block 엔티티가 originalAttributestransformedAttributes 모두에서 동일한 JSON 객체를 참조하기 때문에, 후자 필드에서 수행된 변환이 전자 필드에도 영향을 미칩니다(이는 쿼리에서 나타나는 순서와 무관합니다).

결과적으로 두 필드 모두 프랑스어로 번역됩니다:

{
  "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
            }
          }
        ]
      }
    ]
  }
}

transformedAttributes 필드에 디렉티브 @objectClone을 추가하여 클론된 JSON 객체에 대해 수정이 이루어지도록 함으로써 이 문제를 피할 수 있습니다:

{
  posts {
    blocks(filterBy: { include: "core/heading" } ) {
      originalAttributes: attributes
      transformedAttributes: attributes
        @objectClone
        @underJSONObjectProperty(by: { key: "content" })
          @strTranslate(to: "fr")
    }
  }
}

...결과:

{
  "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
            }
          }
        ]
      }
    ]
  }
}

추가 예시

이 쿼리에서 @underEachArrayItem@underJSONObjectProperty를 래핑하고, @underJSONObjectProperty@strUpperCase를 래핑하여 WP REST API를 통해 가져온 여러 포스트 항목의 "title.rendered" 속성을 대문자로 변환합니다:

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
}

...결과:

{
  "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"
        }
      }
    ]
  }
}