著者は、無料かつオープンソースの基金を寄付の対象として選び、Write for Donations プログラムの一環として寄付しました。
紹介
GraphQLは、フロントエンドとデータソースの間のコミュニケーションを促進するための現代的な解決策です。GraphQLの実装の詳細と機能は、GraphQL スキーマに詳細に記載されています。機能するGraphQLスキーマを作成するには、GraphQLタイプシステムを理解する必要があります。
この記事では、GraphQLのタイプについて学びます。5つの組み込みスカラー型、Enums、ListおよびNon-Nullラップ型、オブジェクト型、およびそれらと連携する抽象インターフェースおよびユニオン型について解説します。各タイプの例を確認し、それらを使用して完全なGraphQLスキーマを構築する方法を学びます。
前提条件
このチュートリアルを最大限に活用するには、以下の理解が必要です:
- GraphQLの基本的な概念についての理解、これはGraphQL入門で説明されています。
- A GraphQL environment, an example of which can be found in How to Set Up a GraphQL API Server in Node.js.
スカラータイプ
GraphQLスキーマ内のすべてのデータは、最終的にさまざまなスカラータイプに解決されます。これらは原始値を表します。GraphQLの応答は木として表現でき、スカラータイプは木の端にある葉です。入れ子になった応答には多くのレベルがありますが、最後のレベルは常にスカラー(またはEnum)タイプに解決されます。GraphQLには、Int
、Float
、String
、Boolean
、ID
の5つの組み込みスカラータイプが付属しています。
Int
Int
は、32ビットの符号付き非小数の数値です。これは小数を含まない符号付き(正または負)の整数です。符号付き32ビット整数の最大値は2,147,483,647
です。これは数値データに使用される2つの組み込みスカラーのうちの1つです。
Float
A Float
is a signed double-precision fractional value. It is a signed (positive or negative) number that contains a decimal point, such as 1.2
. This is the other built-in scalar used for numerical data.
String
A String
is a UTF-8 character sequence. The String
type is used for any textual data. This can also include data like very large numbers. Most custom scalars will be types of string data.
Boolean
A Boolean
is a true
or false
value.
ID
ID
は一意の識別子です。この値は常に文字列としてシリアル化されます。たとえID
が数値であってもです。ID
タイプは一般的にUniversally Unique Identifier (UUID)で表されることがあります。
カスタムスカラー
これらの組み込みスカラーに加えて、scalar
キーワードを使用してカスタムスカラーを定義することができます。カスタムスカラーを使用して、Date
、Time
、またはUrl
などの追加のサーバーレベルの検証が必要なタイプを作成できます。次は、新しいDate
タイプを定義する例です:
scalar Date
サーバーは、この新しいタイプとの対話を処理する方法をGraphQLScalarType
を使用して知っています。
Enumタイプ
Enumタイプ、またはEnumeratorタイプとも呼ばれるものは、可能な値のセットを記述します。
他の「GraphQLでデータを管理する方法」シリーズのチュートリアルからのFantasy Game APIテーマを使用して、ゲームキャラクターのJob
およびSpecies
に対してシステムが受け入れるすべての値に対するenum
を作成するかもしれません。Enumは、次のようにenum
キーワードで定義されます:
"The job class of the character."
enum Job {
FIGHTER
WIZARD
}
"The species or ancestry of the character."
enum Species {
HUMAN
ELF
DWARF
}
この方法では、キャラクターのJob
がFIGHTER
またはWIZARD
であり、誤って"purple"
などのランダムな文字列になることはありません。これは、String
タイプを使用せずにカスタムEnumを作成することによって可能です。Enumは慣例としてすべて大文字で書かれます。
また、Enumは引数で受け入れられる値としても使用できます。たとえば、Hand
enum
を作成して、武器が片手持ち(短剣のような)か両手持ち(重い斧のような)かを示し、それを使用して装備できる武器が1本か2本かを判断することができます:
enum Hand {
SINGLE
DOUBLE
}
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
hand: Hand
}
type Query {
weapons(hand: Hand = SINGLE): [Weapon]
}
Hand
enum
はSINGLE
とDOUBLE
を値として宣言されており、weapons
フィールドの引数にはデフォルト値としてSINGLE
が設定されています。つまり、引数が渡されない場合はSINGLE
にフォールバックします。
NotNullタイプ
多くの言語でプリミティブと見なされるnull
またはundefined
が、組み込みのスカラーのリストから欠落していることに気付くかもしれません。 NullはGraphQLに存在し、値の不在を表します。
すべてのタイプは、デフォルトでGraphQLではnull可能です。したがって、null
は任意の型の有効な応答です。値を必須にするには、GraphQLのNon-Nullタイプに変換する必要があります。Non-Nullは、参照している型を変更するために使用される型修飾子で定義されています。例えば、String
はオプション(またはnullable)の文字列であり、String!
は必須(またはNon-Null)の文字列です。
List Type
A List type in GraphQL is another type modifier. Any type that is wrapped in square brackets ([]
) becomes a List type, which is a collection that defines the type of each item in a list.
たとえば、[Int]
と定義されたタイプはInt
タイプのコレクションになり、[String]
はString
タイプのコレクションになります。Non-NullとListは一緒に使用して、型を必須にしてリストとして定義することができます。例えば、[String]!
のように。
Object Type
もしGraphQLスカラータイプが階層的なGraphQL応答の末端にある”葉”を表すのであれば、Objectタイプは中間の”枝”を表し、GraphQLスキーマのほとんどがObjectの一種です。
オブジェクトは、名前付きのフィールド(キー)のリストと、各フィールドが解決される値の型で構成されています。オブジェクトは、type
キーワードで定義されます。少なくとも1つ以上のフィールドを定義する必要があり、フィールドはGraphQLの内観システムとの競合を避けるために、二重アンダースコア(__
)で始まることはできません。
GraphQLファンタジーゲームAPIの例では、Fighter
オブジェクトを作成して、ゲーム内のキャラクタータイプを表すことができます:
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
}
この例では、Fighter
オブジェクトタイプが宣言され、4つの名前付きフィールドがあります:
id
はNonNullのID
型を返します。name
はNonNullのString
型を返します。level
はInt
型を返します。active
はNonNullのBoolean
型を返します。
宣言の上には、このようにダブルクォーテーションを使用してコメントを追加することもできます:"直接の戦闘能力と強さを持つ英雄。"
。これはタイプの説明として表示されます。
この例では、各フィールドがスカラータイプに解決されますが、オブジェクトフィールドは他のオブジェクトタイプに解決されることもあります。たとえば、Weapon
タイプを作成し、GraphQLスキーマを設定して、Fighter
のweapon
フィールドがWeapon
オブジェクトに解決されるようにすることができます:
"A valiant weapon wielded by a fighter."
type Weapon {
name: String!
attack: Int
range: Int
}
"A hero with direct combat ability and strength."
type Fighter {
id: ID!
name: String!
level: Int
active: Boolean!
weapon: Weapon
}
オブジェクトは、他のオブジェクトのフィールドにネストされることもあります。
ルート操作の種類
GraphQLスキーマへの入り口として機能する3つの特別なオブジェクトがあります:クエリ、ミューテーション、サブスクリプションです。これらはルート操作の種類として知られ、他のどのオブジェクト型と同じルールに従います。
schema
キーワードはGraphQLスキーマへの入り口を表します。ルートのクエリ、ミューテーション、およびサブスクリプションの型はルートschema
オブジェクト上にあります:
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
クエリ型はGraphQLスキーマで必須であり、読み取りリクエストを表します。これはREST APIのGET
と類似しています。次は、Fighter
型のリストを返すルートQuery
オブジェクトの例です:
type Query {
fighters: [Fighter]
}
ミューテーションは書き込みリクエストを表し、これはREST APIのPOST
、PUT
、またはDELETE
に類似しています。次の例では、Mutation
に名前付き引数(input
)を持つaddFighter
フィールドがあります:
type Mutation {
addFighter(input: FighterInput): Fighter
}
最後に、サブスクリプションはイベントストリームに対応し、Webアプリ内でWebsocketと共に使用されます。GraphQL Fantasy APIでは、ランダムな戦闘エンカウンターに使用できるかもしれません:
type Subscription {
randomBattle(enemy: Enemy): BattleResult
}
schema
の入り口は、一部のGraphQL実装では頻繁に抽象化されます。
フィールド引数
GraphQLオブジェクトのフィールドは基本的に値を返す関数であり、任意の関数と同様に引数を受け入れることができます。フィールド引数は、引数の名前に続いて型が定義されます。引数はオブジェクト型以外の任意の型にすることができます。この例では、Fighter
オブジェクトをid
フィールドでフィルタリングできます(これはNonNull ID
型に解決されます):
type Query {
fighter(id: ID!): Fighter
}
この特定の例は、データストアから単一のアイテムを取得するのに便利ですが、引数はフィルタリング、ページネーション、およびその他のより具体的なクエリにも使用できます。
インターフェース型
オブジェクト型と同様に、抽象的なインターフェース型は、名前付きフィールドのリストとそれに関連する値の型で構成されます。インターフェースはオブジェクトの実装のサブセットを定義するために使用され、オブジェクトと全く同じルールに従います。
これまでのスキーマでは、Fighter
オブジェクトを持っていますが、Wizard
、Healer
、その他共通のフィールドを多く共有するがいくつかの違いがあるオブジェクトも作成することが望ましいかもしれません。この場合、共通のフィールドを定義するためにインターフェースを使用し、そのインターフェースの実装となるオブジェクトを作成できます。
次の例では、すべてのキャラクタータイプが持つであろうフィールドを含むBaseCharacter
インターフェースをinterface
キーワードを使用して作成できます:
"A hero on a quest."
interface BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job
}
すべてのキャラクタータイプは、id
、name
、level
、species
、job
というフィールドを持ちます。
今、Fighter
タイプとWizard
タイプがこれら共有フィールドを持っているが、Fighters
はWeapon
を、Wizards
はSpells
を使用すると想像してください。implements
キーワードを使用して、それぞれをBaseCharacter
の実装として区別し、つまり作成されたインターフェースからすべてのフィールドを持たなければならないことを意味します:
"A hero with direct combat ability and strength."
type Fighter implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
weapon: Weapon
}
"A hero with a variety of magical powers."
type Wizard implements BaseCharacter {
id: ID!
name: String!
level: Int!
species: Species
job: Job!
spells: [Spell]
}
Fighter
とWizard
は、必要なフィールドのサブセットを持っているため、BaseCharacter
インターフェースの有効な実装です。
Union Type
別のオブジェクトで使用できる抽象型は、Union型です。 union
キーワードを使用して、応答として有効なオブジェクトのリストを含む型を定義できます。
前のセクションで作成したインターフェースを使用して、Character
Unionを作成できます。これにより、キャラクターをWizard
またはFighter
として定義します:
union Character = Wizard | Fighter
等しい文字(=
)は定義を設定し、パイプ文字(|
)はOR
ステートメントとして機能します。 Unionはオブジェクトまたはインターフェースで構成されている必要があります。スカラータイプはUnionで有効ではありません。
これでキャラクターのリストをクエリすると、Character
Unionが使用され、すべてのWizard
およびFighter
タイプが返される可能性があります。
結論
このチュートリアルでは、GraphQLタイプシステムを定義するさまざまなタイプについて学びました。最も基本的なタイプはスカラータイプであり、これらはスキーマツリー上の葉として機能し、Int
、Float
、String
、Boolean
、ID
、およびGraphQLの実装が作成することを決定するカスタムスカラーで構成されます。Enumは定数値の有効なリストであり、String
として単に宣言するよりも応答をより細かく制御する必要がある場合に使用できます。これらもスキーマツリー上の葉です。ListおよびNon-Nullタイプは、型修飾子またはラッピングタイプとして知られ、コレクションまたは必須として他のタイプを定義できます。オブジェクトはスキーマツリーの枝であり、GraphQLスキーマのほとんどすべてがquery
、mutation
、subscription
エントリーポイントを含むオブジェクトの一種です。InterfaceおよびUnionタイプは、オブジェクトを定義するのに役立つ抽象タイプです。
さらに学習するには、How to Set Up a GraphQL API Server in Node.jsチュートリアルを読んで、動作するGraphQLサーバー環境を作成および変更する練習をすることができます。
Source:
https://www.digitalocean.com/community/conceptual-articles/understanding-the-graphql-type-system