Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

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について話したい場合は、グッズを販売するバーに行きます。


  1. TCmallocを使用したRubyのメモリ割り当てのプロファイリング

    Rubyではメモリ割り当てはどのように機能しますか? Rubyはページと呼ばれるチャンクでメモリを取得し、新しいオブジェクトはここに保存されます。 次に… これらのページがいっぱいになると、より多くのメモリが必要になります。 Rubyは、mallocを使用してオペレーティングシステムからより多くのメモリを要求します 機能。 このmalloc 関数はオペレーティングシステム自体の一部ですが、使用できる代替の実装があります。 それらの実装の1つは、Googleのtcmallocです。 TCmallocはGoogleパフォーマンスツールスイートの一部です。 これらのツールを使用し

  2. Rubyでパーサーを構築する方法

    構文解析は、一連の文字列を理解し、それらを理解できるものに変換する技術です。正規表現を使用することもできますが、必ずしもその仕事に適しているとは限りません。 たとえば、HTMLを正規表現で解析することはおそらく良い考えではないことは一般的な知識です。 Rubyには、この作業を実行できるnokogiriがありますが、独自のパーサーを作成することで多くのことを学ぶことができます。始めましょう! Rubyでの解析 パーサーの中核はStringScannerです クラス。 このクラスは、文字列のコピーと位置ポインタを保持します。ポインタを使用すると、特定のトークンを検索するために文字列をトラバ