GraphQL 스키마가 지원하는 쿼리에 대한 정보를 요청하는 것이 종종 유용합니다. GraphQL을 사용하면 내성 시스템을 사용하여 그렇게 할 수 있습니다!1)
Star Wars 예제의 경우 starWarsIntrospection-test.ts 파일에는 자체 검사 시스템을 보여주는 여러 쿼리가 포함되어 있으며 참조 구현의 자체 검사 시스템을 실행하기 위해 실행할 수 있는 테스트 파일입니다.2)
우리는 유형 시스템을 설계했기 때문에 어떤 유형이 사용 가능한지 알 수 있지만, 그렇지 않은 경우 쿼리의 루트 유형에서 항상 사용할 수 있는 __schema 필드를 쿼리하여 GraphQL에 요청할 수 있습니다. 이제 그렇게 하고 어떤 유형을 사용할 수 있는지 물어보겠습니다.3)
{
__schema {
types {
name
}
}
}
{
"data": {
"__schema": {
"types": [
{
"name": "Query"
},
{
"name": "String"
},
{
"name": "ID"
},
{
"name": "Mutation"
},
{
"name": "Episode"
},
{
"name": "Character"
},
{
"name": "Int"
},
{
"name": "LengthUnit"
},
{
"name": "Human"
},
{
"name": "Float"
},
{
"name": "Droid"
},
{
"name": "FriendsConnection"
},
{
"name": "FriendsEdge"
},
{
"name": "PageInfo"
},
{
"name": "Boolean"
},
{
"name": "Review"
},
{
"name": "ReviewInput"
},
{
"name": "Starship"
},
{
"name": "SearchResult"
},
{
"name": "__Schema"
},
{
"name": "__Type"
},
{
"name": "__TypeKind"
},
{
"name": "__Field"
},
{
"name": "__InputValue"
},
{
"name": "__EnumValue"
},
{
"name": "__Directive"
},
{
"name": "__DirectiveLocation"
}
]
}
}
}
우와 종류가 많네요! 그들은 무엇인가? 그룹화해 보겠습니다.4)
__Schema, __Type, __TypeKind, __Field, __InputValue, __EnumValue, __Directive : 이 모든 항목 앞에는 이중 밑줄이 표시되어 내부 검사 시스템의 일부임을 나타냅니다.7)이제 어떤 쿼리를 사용할 수 있는지 살펴보기에 좋은 위치를 찾아 보겠습니다. 유형 시스템을 설계할 때 모든 쿼리가 시작되는 유형을 지정했습니다. 그것에 대해 내성 시스템에 물어보자!8)
{
__schema {
queryType {
name
}
}
}
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
}
}
}
}
그리고 그것은 우리가 유형 시스템 섹션에서 말한 것과 일치합니다. 쿼리 유형은 우리가 시작할 곳입니다! 여기에서 명명한 것은 관례에 따른 것입니다. 쿼리 유형의 이름을 다른 이름으로 지정할 수 있으며 쿼리의 시작 유형으로 지정했다면 여전히 여기에 반환되었을 것입니다. 하지만 이름을 Query로 지정하는 것은 유용한 규칙입니다.9)
하나의 특정 유형을 조사하는 것이 종종 유용합니다. Droid 유형을 살펴보겠습니다.10)
{
__type(name: "Droid") {
name
}
}
{
"data": {
"__type": {
"name": "Droid"
}
}
}
하지만 Droid에 대해 더 알고 싶다면 어떻게 해야 할까요? 예를 들어 인터페이스인가 객체인가?11)
{
__type(name: "Droid") {
name
kind
}
}
{
"data": {
"__type": {
"name": "Droid",
"kind": "OBJECT"
}
}
}
kind는 값 중 하나가 OBJECT인 __TypeKind 열거형을 반환합니다. 대신 Character에 대해 물으면 인터페이스라는 것을 알 수 있습니다.12)
{
__type(name: "Character") {
name
kind
}
}
{
"data": {
"__type": {
"name": "Character",
"kind": "INTERFACE"
}
}
}
객체가 어떤 필드를 사용할 수 있는지 아는 것이 유용하므로 Droid에 대한 내성 시스템에 물어보겠습니다.13)
{
__type(name: "Droid") {
name
fields {
name
type {
name
kind
}
}
}
}
{
"data": {
"__type": {
"name": "Droid",
"fields": [
{
"name": "id",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "name",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "friends",
"type": {
"name": null,
"kind": "LIST"
}
},
{
"name": "friendsConnection",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "appearsIn",
"type": {
"name": null,
"kind": "NON_NULL"
}
},
{
"name": "primaryFunction",
"type": {
"name": "String",
"kind": "SCALAR"
}
}
]
}
}
}
그것들은 우리가 Droid에서 정의한 우리의 필드입니다!14)
id는 거기에서 약간 이상해 보입니다. 유형에 대한 이름이 없습니다. NON_NULL 종류의 “래퍼” 유형이기 때문입니다. 해당 필드의 유형에 대해 ofType을 쿼리하면 ID 유형이 발견되어 이것이 null이 아닌 ID임을 알려줍니다.15)
유사하게, friend와 appearsIn은 모두 LIST 래퍼 유형이기 때문에 이름이 없습니다. 우리는 이러한 유형에 대해 ofType을 쿼리할 수 있으며 이는 목록이 무엇인지 알려줍니다.16)
{
__type(name: "Droid") {
name
fields {
name
type {
name
kind
ofType {
name
kind
}
}
}
}
}
{
__type(name: "Droid") {
name
fields {
name
type {
name
kind
ofType {
name
kind
}
}
}
}
}
툴링에 특히 유용한 인트로스펙션 시스템의 기능으로 끝내자. 시스템에 문서를 요청합시다!17)
{
__type(name: "Droid") {
name
description
}
}
{
"data": {
"__type": {
"name": "Droid",
"description": null
}
}
}
따라서 우리는 내성을 사용하여 유형 시스템에 대한 문서에 액세스하고 문서 브라우저 또는 풍부한 IDE 환경을 만들 수 있습니다.18)
이것은 자기 성찰 시스템의 표면을 긁은 것뿐입니다. 열거형 값, 유형이 구현하는 인터페이스 등을 쿼리할 수 있습니다. 우리는 자기 성찰 시스템 자체를 성찰할 수도 있습니다. 사양은 “인트로스펙션” 섹션에서 이 주제에 대해 더 자세히 설명하고, GraphQL.js의 내성 파일에는 사양을 준수하는 GraphQL 쿼리 내성 시스템을 구현하는 코드가 포함되어 있습니다.19)
__schema field, always available on the root type of a Query. Let's do so now, and ask what types are available.__TypeKind enum, one of whose values is OBJECT. If we asked about Character instead we'd find that it is an interface:NON_NULL. If we queried for ofType on that field's type, we would find the ID type there, telling us that this is a non-null ID.