将来を見据えたウェブ・アプリケーションの構築:The Codestのエキスパート・チームによる洞察
The Codestが、最先端技術を駆使してスケーラブルでインタラクティブなウェブアプリケーションを作成し、あらゆるプラットフォームでシームレスなユーザー体験を提供することにどのように秀でているかをご覧ください。The Codestの専門知識がどのようにデジタルトランスフォーメーションとビジネス...
この記事では、GraphQLにおけるポリモーフィズムの使い方を紹介する。しかしその前に、ポリモーフィズムとGraphQLが何であるかを思い出しておく価値がある。
ポリモーフィズム の重要な構成要素である。 オブジェクト指向プログラミング.物事を単純化するために、これは異なるクラスのオブジェクトが同じインターフェースにアクセスできるという事実に基づいている。つまり Ruby開発者 が得られる。 多型 の3つである:
継承 は、親クラスと子クラス(つまり親クラスを継承するクラス)を作成することにあります。子クラスは親クラスの機能を受け継ぎ、また機能を変更したり追加したりすることができます。
例
クラス ドキュメント
attr_reader :名前
終了
クラス PDFDocument < ドキュメント
def 拡張
:pdf
終了
終了
class ODTDocument < ドキュメント
def 拡張
:odt
終了
終了
モジュール ルビー には多くの使い方がある。そのひとつがミックスインだ(ミックスインについては 究極のブレークダウンルビー対Python).Rubyのミキシンは、他のプログラミング言語のインターフェイスと同じように使うことができます(例えば ジャワを含むオブジェクトに共通するメソッドを定義することができます。モジュールには読み取り専用のメソッドを含めるのがよい習慣です。つまり、このオブジェクトの状態を変更しないメソッドです。
例
課税モジュール
デフタックス
価格 * 0.23
終了
終了
クラス Car
課税対象を含む
attr_reader :価格
終了
クラス Book
課税対象を含む
attr_reader :価格
終了
これは動的型付け言語の重要な特徴のひとつである。この名前は、「アヒルのように見え、アヒルのように泳ぎ、アヒルのように鳴くなら、それはおそらくアヒルである」という有名なテストに由来する。これは プログラマー は、与えられたオブジェクトがどのクラスに属しているかに関心を持つ必要はない。重要なのは、このオブジェクトに対して呼び出せるメソッドである。
上記の例で定義したクラスを使用する:
クラス 車
attr_reader :価格
def initialize(price)
価格 = 価格
終了
終了
クラス Book
attr_reader :価格
def initialize(price)
価格 = 価格
終了
終了
car = Car.new(20.0)
book = Book.new(10.0)
[車, 本].map(&:価格)
GraphQL はAPI用の比較的新しいクエリー言語である。その利点は、非常にシンプルな構文を持っていること、さらに、各顧客が望むものを正確に得ることができ、それ以外は何も得ることができないため、クライアントが正確に得たいものを決めることができることである。
のサンプルクエリ GraphQL:
{
すべてのユーザー
ユーザー
id
ログイン
電子メール
}
}
}
回答例
{
"allUsers":{
"users":[
{
"id":1,
"login":"user1"、
"email":"[email protected]"
},
{
"id":2,
"login":"user2"、
"email":"[email protected]"
},
]
}
現時点で知るべきことはこれだけだろう。では、本題に入ろう。
問題とその解決策を最もよく理解するために、例を作ってみよう。その例が独創的で、かつかなり現実的なものであればいい。私たち一人ひとりがいつか遭遇する可能性のあるものだ。動物はどうだろう?そうだ!いいアイデアだ!
で書かれたバックエンドアプリケーションがあるとする。 Ruby on Rails.これは、上記のスキームを処理するためにすでに適応されている。また、すでに GraphQL を構成した。クライアントが以下の構造で問い合わせを行えるようにしたい:
{
allZoos : {
動物園{
名前
都市
動物: {
...
}
}
}
}
足りない情報を得るためには、3つの点の代わりに何を入れればいいのか。
以下、目標を達成するために必要なステップを紹介しよう。
まず、allZoosというクエリが何を意味するのかを定義する必要がある。そのためには、ファイルapp/graphql/types/query_type.rb
とクエリーを定義する:
モジュール Types
class QueryType < Types::BaseObject
フィールド :all_zoos, [Types::ZooType], null: false
def all_zoos
Zoo.all
終了
終了
終了
クエリーはすでに定義されている。次は戻り値の型を定義する番だ。
最初に必要なタイプはZooTypeです。ファイルで定義しましょう。 app/graphql/types/ zoo_type.rb
:
モジュール Types
class ZooType < Types::BaseObject
field :name, String, null: false
field :city, String, null: false
field :animals, [Types::AnimalType], null: false
終了
終了
次にAnimalType型を定義する:
モジュール Types
class AnimalType < Types::BaseUnion
指定可能な型 ElephantType, CatType, DogType
def self.resolve_type(obj, ctx)
if obj.is_a?(Elephant)
ElephantType
elsif obj.is_a?(Cat)
CatType
elsif obj.is_a?(Dog)
DogType
end
end
end
end
私たちは何を見るのだろうか? コード 上記?
タイプ::ベースユニオン
.self.resolve_object(obj, ctx)、
これは、与えられたオブジェクトの型を返さなければならない。次のステップは、動物の種類を定義することである。しかし、いくつかのフィールドはすべての動物に共通であることがわかっている。それらをAnimalInterface型に含めよう:
モジュール Types
モジュール AnimalInterface
include Types::BaseInterface
field :name, String, null: false
field :age, 整数, null: false
終了
終了
このインターフェイスがあれば、特定の動物のタイプを定義することができる:
モジュール Types
class ElephantType < Types::BaseObject
Types::AnimalInterface を実装
フィールド :trunk_length, Float, null: false
終了
終了
モジュール Types
class CatType < Types::BaseObject
Types::AnimalInterface を実装しています。
フィールド :hair_type, String, null: false
終了
終了
モジュール Types
class DogType < Types::BaseObject
Types::AnimalInterface を実装
フィールド :breed, String, null: false
終了
終了
そうだ!準備完了!最後の質問:クライアント側で行ったことをどのように使えばいいのでしょうか?
{
allZoos : {
動物園{
名前
都市
動物: {
名前
... on ElephantType { {...
名前
年齢
体幹の長さ
}
... on CatType { ...
名前
年齢
ヘアタイプ
}
... on DogType {
名前
年齢
犬種
}
}
ここで追加の__typenameフィールドを使えば、与えられた要素の正確な型を返すことができる(例:CatType)。回答例はどのようになるでしょうか?
{
"allZoos":[
{
"name":"Natura Artis Magistra"、
"city":"アムステルダム"、
"animals":[
{
"__typename":"エレファントタイプ"
"name":"フランコ"、
"age":28,
「幹の長さ9.27
},
{
"__typename":"DogType"
"name":"Jack"、
"age":9,
犬種「ジャック・ラッセル・テリア
},
]
}
]
}
この方法の欠点は明らかである。クエリーでは、すべての動物がこれらのフィールドを持っていることがわかっているにもかかわらず、それぞれのタイプに名前と年齢を入力しなければならない。これは、コレクションにまったく異なるオブジェクトが含まれている場合には気にならない。しかし、この場合、動物はほとんどすべてのフィールドを共有している。どうにか改善できないだろうか?
もちろんだ!ファイルに最初の変更を加える app/graphql/types/zoo_type.rb
:
モジュール Types
class ZooType < Types::BaseObject
field :name, String, null: false
field :city, String, null: false
field :animals, [Types::AnimalInterface], null: false
終了
終了
私たちはもはや、これまで定義してきた組合を必要としない。次のように変更する。 タイプ::アニマルタイプ
への Types::AnimalInterface
.
次のステップは、以下の型を返す関数を追加することである。 タイプ ::動物インターフェース
さらに、直接使われることのない型であるorphan_typesのリストも追加した:
モジュール Types
モジュール AnimalInterface
include Types::BaseInterface
field :name, String, null: false
field :age, 整数, null: false
definition_methods do
def resolve_type(obj, ctx)
if obj.is_a?(Elephant)
象型
elsif obj.is_a?(Cat)
CatType
elsif obj.is_a?(Dog)
DogType
end
end
end
orphan_types Types::ElephantType, Types::CatType, Types::DogType
end
終了
このシンプルな手順のおかげで、クエリーはそれほど複雑な形をしていない:
{
allZoos : {
動物園{
名前
都市
動物: {
名前
名前
年齢
... on ElephantType { {...
幹の長さ
}
... on CatType { 毛の長さ } ... on CatType { 毛の長さ
毛の長さ
}
... on DogType { 犬種
犬種
}
}
}
}
}
GraphQL は本当に素晴らしいソリューションだ。まだ知らない人は試してみて。信じてほしい。これは、例えばREST APIに現れる問題を解決する上で素晴らしい仕事をしてくれる。上で示したように、 多型 は、そのための本当の障害ではない。私はそれに取り組むための2つの方法を提示した。
リマインダー
続きを読む