Need help with graphlient?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

ashkan18
151 Stars 23 Forks MIT License 144 Commits 17 Opened issues

Description

Ruby GraphQL Client

Services available

!
?

Need anything else?

Contributors list

# 15,851
Ruby
slack
Rails
coffees...
49 commits
# 217,045
GraphQL
slack
React N...
coffees...
43 commits
# 111,342
Ruby
Shell
Elixir
Swift
7 commits
# 20,522
Ruby
Rails
coffees...
Jekyll
4 commits
# 392,898
travis-...
CSS
continu...
Kuberne...
3 commits
# 3,088
Svelte
bitbuck...
graphql...
Express
1 commit
# 357,581
dashboa...
Rails
C
HTML
1 commit
# 5,675
Rails
HTML
Flask
CSS
1 commit
# 74,609
Ruby
React N...
feed-re...
rss-rea...
1 commit

Graphlient

Gem Version Build Status

A friendlier Ruby client for consuming GraphQL-based APIs. Built on top of your usual graphql-client, but with better defaults, more consistent error handling, and using the faraday HTTP client.

Installation

Add the following line to your Gemfile.

gem 'graphlient'

Usage

Create a new instance of

Graphlient::Client
with a URL and optional headers/http_options.
client = Graphlient::Client.new('https://test-graphql.biz/graphql',
  headers: {
    'Authorization' => 'Bearer 123'
  },
  http_options: {
    read_timeout: 20,
    write_timeout: 30
  }
)

| httpoptions | default | type | |---------------|---------|---------| | readtimeout | nil | seconds | | write_timeout | nil | seconds |

The schema is available automatically via

.schema
.
client.schema # GraphQL::Schema

Make queries with

query
, which takes a String or a block for the query definition.

With a String.

response = client.query <

With a block.

response = client.query do
  query do
    invoice(id: 10) do
      id
      total
      line_items do
        price
        item_type
      end
    end
  end
end

This will call the endpoint setup in the configuration with

POST
, the
Authorization
header and
query
as follows.
query {
  invoice(id: 10) {
    id
    total
    line_items {
      price
      item_type
    }
  }
}

A successful response object always contains data which can be iterated upon. The following example returns the first line item's price.

response.data.invoice.line_items.first.price

You can also execute mutations the same way.

response = client.query do
  mutation do
    createInvoice(input: { fee_in_cents: 12_345 }) do
      id
      fee_in_cents
    end
  end
end

The successful response contains data in

response.data
. The following example returns the newly created invoice's ID.
response.data.create_invoice.first.id

Schema storing and loading on disk

To reduce requests to graphql API you can cache schema:

client = Client.new(url, schema_path: 'config/your_graphql_schema.json')
client.schema.dump! # you only need to call this when graphql schema changes

Error Handling

Unlike graphql-client, Graphlient will always raise an exception unless the query has succeeded.

All errors inherit from

Graphlient::Errors::Error
if you need to handle them in bulk.

Executing Parameterized Queries and Mutations

Graphlient can execute parameterized queries and mutations by providing variables as query parameters.

The following query accepts an array of IDs.

With a String.

query = <

With a block.

client.query(ids: [42]) do
  query(ids: [:int]) do
    invoices(ids: :ids) do
      id
      fee_in_cents
    end
  end
end

Graphlient supports following Scalar types for parameterized queries by default: -

:id
maps to
ID
-
:boolean
maps to
Boolean
-
:float
maps to
Float
-
:int
maps to
Int
-
:string
maps to
String

You can use any of the above types with

!
to make it required or use them in
[]
for array parameters.

For any other custom types, graphlient will simply use

to_s
of the symbol provided for the type, so
query(ids: [:InvoiceType!])
will result in
query($ids: [InvoiceType!])
.

The following mutation accepts a custom type that requires

fee_in_cents
.
client.query(input: { fee_in_cents: 12_345 }) do
  mutation(input: :createInvoiceInput!) do
    createInvoice(input: :input) do
      id
      fee_in_cents
    end
  end
end

Parse and Execute Queries Separately

You can

parse
and
execute
queries separately with optional variables. This is highly recommended as parsing a query and validating a query on every request adds performance overhead. Parsing queries early allows validation errors to be discovered before request time and avoids many potential security issues.
# parse a query, returns a GraphQL::Client::OperationDefinition
query = client.parse do
  query(ids: [:int]) do
    invoices(ids: :ids) do
      id
      fee_in_cents
    end
  end
end

execute a query, returns a GraphQL::Client::Response

client.execute query, ids: [42]

Or pass in a string instead of a block:

# parse a query, returns a GraphQL::Client::OperationDefinition
query = client.parse <

Dynamic vs. Static Queries

Graphlient uses graphql-client, which recommends building queries as static module members along with dynamic variables during execution. This can be accomplished with graphlient the same way.

Create a new instance of

Graphlient::Client
with a URL and optional headers.
module SWAPI
  Client = Graphlient::Client.new('https://test-graphql.biz/graphql',
    headers: {
      'Authorization' => 'Bearer 123'
    },
    allow_dynamic_queries: false
  )
end

The schema is available automatically via

.schema
.
SWAPI::Client.schema # GraphQL::Schema

Define a query.

module SWAPI
  InvoiceQuery = Client.parse do
    query(id: :int) do
      invoice(id: :id) do
        id
        fee_in_cents
      end
    end
  end
end

Execute the query.

response = SWAPI::Client.execute(SWAPI::InvoiceQuery, id: 42)

Note that in the example above the client is created with

allow_dynamic_queries: false
(only allow static queries), while graphlient defaults to
allow_dynamic_queries: true
(allow dynamic queries). This option is marked deprecated, but we're proposing to remove it and default it to
true
in graphql-client#128.

Generate Queries with Graphlient::Query

You can directly use

Graphlient::Query
to generate raw GraphQL queries.
query = Graphlient::Query.new do
  query do
    invoice(id: 10) do
      line_items
    end
  end
end

query.to_s

"\nquery {\n invoice(id: 10){\n line_items\n }\n }\n"

Create API Client Classes with Graphlient::Extension::Query

You can include

Graphlient::Extensions::Query
in your class. This will add a new
method_missing
method to your context which will be used to generate GraphQL queries.
include Graphlient::Extensions::Query

query = query do invoice(id: 10) do line_items end end

query.to_s

"\nquery{\n invoice(id: 10){\n line_items\n }\n }\n"

Swapping the HTTP Stack

You can swap the default Faraday adapter for

Net::HTTP
.
client = Graphlient::Client.new('https://test-graphql.biz/graphql',
  http: Graphlient::Adapters::HTTP::HTTPAdapter
)

Testing with Graphlient and RSpec

Use Graphlient inside your RSpec tests in a Rails application or with

Rack::Test
against your actual application.
require 'spec_helper'

describe App do include Rack::Test::Methods

def app # ... end

let(:client) do Graphlient::Client.new('http://test-graphql.biz/graphql') do |client| client.http do |h| h.connection do |c| c.adapter Faraday::Adapter::Rack, app end end end end

context 'an invoice' do let(:result) do client.query do query do invoice(id: 10) do id end end end end

it 'can be retrieved' do
  expect(result.data.invoice.id).to eq 10
end

end end

Alternately you can

stub_request
with Webmock.
describe App do
  let(:url) { 'http://example.com/graphql' }
  let(:client) { Graphlient::Client.new(url) }

before do stub_request(:post, url).to_return( status: 200, body: DummySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY).to_json ) end

it 'retrieves schema' do expect(client.schema).to be_a Graphlient::Schema end end

In order to stub the response to actual queries, dump the schema into a JSON file and specify it via schema_path as follows.

describe App do
  let(:url) { 'http://graph.biz/graphql' }
  let(:client) { Graphlient::Client.new(url, schema_path: 'spec/support/fixtures/invoice_api.json') }
  let(:query) do
    < {
        'invoice' => {
          'id' => '42',
          'feeInCents' => 2000
        }
      }
    }.to_json
  end

before do stub_request(:post, url).to_return( status: 200, body: json_response ) end

it 'returns invoice fees' do response = client.query(query) expect(response.data).to be_truthy expect(response.data.invoice.id).to eq('42') expect(response.data.invoice.fee_in_cents).to eq(2000) end end

License

MIT License, see LICENSE

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.