Rubyを使用したGraphQLのインストルメンタルイントロ
開発者がGraphQLの素晴らしさを称賛するのを聞いたことがあるかもしれません。このシリーズでは、テクノロジーを使用してテクノロジーを学びたいと考えています。この記事では、GraphQLを使用するサンプルアプリケーションについて説明します。
GraphQLとは
GraphQLは、APIの構築に使用できるクエリ言語およびランタイムです。開発スタックではRESTAPIと同様の位置を占めますが、柔軟性が高くなります。 RESTとは異なり、GraphQLでは応答形式とコンテンツをクライアントが指定できます。 SQL SELECT
と同じように ステートメントを使用するとクエリ結果を指定でき、GraphQLを使用すると返されるJSONデータ構造を指定できます。 SQLの例えに従って、GraphQLは WHERE
を提供しません 句ですが、応答のデータを提供する必要があるアプリケーションオブジェクトのフィールドを識別します。
GraphQLは、その名前が示すように、アプリケーションがデータのグラフであるかのようにAPIをモデル化します。この説明は、アプリケーションの表示方法とは異なる場合がありますが、ほとんどのシステムで使用されているモデルです。 JSONは単なる有向グラフであるため、JSONで表すことができるデータはグラフです。アプリケーションをAPIを介してグラフモデルを提示するものと考えると、GraphQLがはるかに理解しやすくなります。
アプリケーションでのGraphQLの使用
抽象的にGraphQLについて説明したので、データモデルまたはグラフの定義から始めて、GraphQLを使用するアプリケーションを実際に構築することに取り掛かりましょう。昨年、新しい趣味を始めました。私はエレクトリックアップライトベースの演奏と音楽全般について学んでいるので、デモアプリを思いついたときに音楽関連の例が思い浮かびました。
この例のオブジェクトタイプはArtistです。 と歌 。 アーティスト 複数の曲がある と歌 アーティストに関連付けられています 。各オブジェクトタイプには、 name
などの属性があります 。
APIを定義する
GraphQLは、GraphQL仕様で「型システム定義言語」と呼ばれることもあるSDL(スキーマ定義言語)を使用します。 GraphQLタイプは、理論的には任意の言語で定義できますが、最も一般的な非依存言語はSDLであるため、SDLを使用してAPIを定義しましょう。
type Artist {
name: String!
songs: [Song]
origin: [String]
}
type Song {
name: String!
artist: Artist
duration: Int
release: String
}
アーティスト name
があります つまり、 String
。感嘆符は、フィールドが non-null
であることを意味します 。 曲コード> 歌の配列です オブジェクト、および
origin
これはString
配列。 歌 似ていますが、1つの奇数フィールドがあります。 リリース
フィールドは時刻または日付型である必要がありますが、GraphQLにはその型がコア型として定義されていません。異なるGraphQL実装間の完全な移植性のために、 String
使用されている。使用するGraphQL実装には、 Time
があります タイプが追加されたので、曲を変更しましょう release
となるように定義します フィールドはTime
タイプ。戻り値はString
になります 、ただし、タイプを Time
に設定します APIをより正確に文書化します。
release: Time
最後のステップは、1つ以上のオブジェクトを取得する方法を説明することです。これはルートと呼ばれ、クエリの場合はクエリルートと呼ばれます。ルートには、 artist
というフィールドまたはメソッドが1つだけあります。 アーティストのname
が必要になります 。
type Query {
artist(name: String!): Artist
}
アプリケーションの作成
これをアプリケーションでどのように使用するかを見てみましょう。 Ruby用のGraphQLサーバーにはいくつかの実装があります。一部のアプローチでは、上記のSDLを同等のRubyに変換する必要があります。私が構築したHTTPサーバーであるAgooは、SDL定義をそのまま使用し、Rubyコードは単純なバニラRubyであるため、これを使用します。
RubyクラスはGraphQLタイプと一致することに注意してください。 Rubyクラス名をGraphQLタイプ名と一致させることで、不要な複雑さを追加することはありません。
class Artist
attr_reader :name
attr_reader :songs
attr_reader :origin
def initialize(name, origin)
@name = name
@songs = []
@origin = origin
end
# Only used by the Song to add itself to the artist.
def add_song(song)
@songs << song
end
end
class Song
attr_reader :name # string
attr_reader :artist # reference
attr_reader :duration # integer
attr_reader :release # time
def initialize(name, artist, duration, release)
@name = name
@artist = artist
@duration = duration
@release = release
artist.add_song(self)
end
end
メソッドはRubyクラスのフィールドと一致します。メソッドには引数がないか、 args ={}
であることに注意してください。 。これはGraphQLAPIが期待するものであり、ここでの実装はそれに続きます。 初期化コード> 後で説明するように、メソッドを使用して例のデータを設定します。
クエリルートクラスも定義する必要があります。 アーティスト
に注意してください SDLのQuery
に一致するメソッド ルートタイプ。 attr_reader
アーティスト
の場合 も追加されました。そのフィールドをQuery
に追加するだけで、APIに公開されます。 SDLドキュメントを入力します。
class Query
attr_reader :artists
def initialize(artists)
@artists = artists
end
def artist(args={})
@artists[args['name']]
end
end
GraphQLルート(クエリルートと混同しないでください)は、クエリルートの上にあります。 GraphQLは、オプションで3つのフィールドを持つように定義しています。この場合、Rubyクラスは query
に実装されます 分野。イニシャライザーは、私が聴きたいニュージーランドのインディーバンドのデータをロードします。
class Schema
attr_reader :query
attr_reader :mutation
attr_reader :subscription
def initialize()
# Set up some data for testing.
artist = Artist.new('Fazerdaze', ['Morningside', 'Auckland', 'New Zealand'])
Song.new('Jennifer', artist, 240, Time.utc(2017, 5, 5))
Song.new('Lucky Girl', artist, 170, Time.utc(2017, 5, 5))
Song.new('Friends', artist, 194, Time.utc(2017, 5, 5))
Song.new('Reel', artist, 193, Time.utc(2015, 11, 2))
@artists = {artist.name => artist}
@query = Query.new(@artists)
end
end
最終的な設定は実装固有です。ここで、サーバーは /graphql
のハンドラーを含むように初期化されます HTTPリクエストパスが開始されます。
Agoo::Server.init(6464, 'root', thread_count: 1, graphql: '/graphql')
Agoo::Server.start()
次に、GraphQLの実装は、前に定義したSDL( $ songs_sdl
)で構成されます。 )その後、サーバーがリクエストを処理している間、アプリケーションはスリープします。
Agoo::GraphQL.schema(Schema.new) {
Agoo::GraphQL.load($songs_sdl)
}
sleep
この例のコードはGitHubにあります。
APIの使用
APIをテストするには、Webブラウザー、Postman、または curl
を使用できます。 。
これを試すGraphQLクエリは次のようになります:
{
artist(name:"Fazerdaze") {
name
songs{
name
duration
}
}
}
クエリはアーティストを要求します 名前付きFazerdaze
name
を返します およびsongs
JSONドキュメントで。 曲ごとに 名前コード> および
duration
歌の JSONオブジェクトで返されます。出力は次のようになります。
{
"data": {
"artist": {
"name": "Fazerdaze",
"songs": [
{
"name": "Jennifer",
"duration": 240
},
{
"name": "Lucky Girl",
"duration": 170
},
{
"name": "Friends",
"duration": 194
},
{
"name": "Reel",
"duration": 193
}
]
}
}
}
クエリ内のオプションの空白を削除した後、curlで作成されたHTTPGETはそのコンテンツを返す必要があります。
curl -w "\n" 'localhost:6464/graphql?query=\{artist(name:"Fazerdaze")\{name,songs\{name,duration\}\}\}&indent=2'
クエリを変更して、 duration
を置き換えてみてください release
を使用 RubyTimeがJSON文字列に変換されることに注意してください。
曲のエンディング
GraphQLで遊んで楽しんだので、タグを付けて、途中で何かを学んだことを願っています。ありがとう、あなたは素晴らしい聴衆でした。もっとRubyについて話したい場合は、グッズを販売するバーに行きます。
-
TCmallocを使用したRubyのメモリ割り当てのプロファイリング
Rubyではメモリ割り当てはどのように機能しますか? Rubyはページと呼ばれるチャンクでメモリを取得し、新しいオブジェクトはここに保存されます。 次に… これらのページがいっぱいになると、より多くのメモリが必要になります。 Rubyは、mallocを使用してオペレーティングシステムからより多くのメモリを要求します 機能。 このmalloc 関数はオペレーティングシステム自体の一部ですが、使用できる代替の実装があります。 それらの実装の1つは、Googleのtcmallocです。 TCmallocはGoogleパフォーマンスツールスイートの一部です。 これらのツールを使用し
-
Rubyでパーサーを構築する方法
構文解析は、一連の文字列を理解し、それらを理解できるものに変換する技術です。正規表現を使用することもできますが、必ずしもその仕事に適しているとは限りません。 たとえば、HTMLを正規表現で解析することはおそらく良い考えではないことは一般的な知識です。 Rubyには、この作業を実行できるnokogiriがありますが、独自のパーサーを作成することで多くのことを学ぶことができます。始めましょう! Rubyでの解析 パーサーの中核はStringScannerです クラス。 このクラスは、文字列のコピーと位置ポインタを保持します。ポインタを使用すると、特定のトークンを検索するために文字列をトラバ