https://github.com/tb/northwind-graphql-ruby
Northwind graphql-ruby
https://github.com/tb/northwind-graphql-ruby
api demo-app graphql rails workshops
Last synced: 12 months ago
JSON representation
Northwind graphql-ruby
- Host: GitHub
- URL: https://github.com/tb/northwind-graphql-ruby
- Owner: tb
- Created: 2017-10-04T19:54:04.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2019-02-03T10:33:18.000Z (over 7 years ago)
- Last Synced: 2025-04-28T01:37:24.267Z (about 1 year ago)
- Topics: api, demo-app, graphql, rails, workshops
- Language: Ruby
- Homepage: http://northwind-graphql-ruby.herokuapp.com/
- Size: 371 KB
- Stars: 24
- Watchers: 1
- Forks: 4
- Open Issues: 7
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# northwind-graphql-ruby
by [GraphQL Developers @ Selleo](https://selleo.com/graphql-expert-developers-team)
[](https://travis-ci.org/tb/northwind-graphql-ruby)
## [Demo](http://northwind-graphql-ruby.herokuapp.com)

## Initial project setup
gem install rails
rails new northwind-graphql-ruby --api --database=postgresql
echo northwind-graphql-ruby > northwind-graphql-ruby/.ruby-gemset
echo 2.4.2 > northwind-graphql-ruby/.ruby-version
cd northwind-graphql-ruby
gem install bundler
## Setup data
rake db:setup
See [Entity-Relationship Diagrams PDF](erd.pdf)
## Setup GraphQL
Add to Gemfile
gem 'graphql'
gem 'batch-loader'
group :development do
# ...
# graphiql in development https://github.com/rmosolgo/graphiql-rails/issues/13#issuecomment-256256255
gem 'sass-rails'
gem 'uglifier'
gem 'coffee-rails'
gem 'graphiql-rails'
end
Then run
bundle
rails generate graphql:install
Add the engine to `routes.rb`
Rails.application.routes.draw do
post "/graphql", to: "graphql#execute"
if Rails.env.development?
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
end
end
And start server
rails s
open http://localhost:3000/graphiql
Query GraphQL API
query { testField }
Read [Introduction to GraphQL](http://graphql.org/learn/)
## Types
GraphQL queries begin from [root types](http://graphql-ruby.org/schema/root_types.html): query, mutation, and subscription (experimental).
[Types](http://graphql-ruby.org/types/introduction.html) describe objects and values in a system.
To query and mutate models we will define two types for each model
Types::SupplierType = GraphQL::ObjectType.define do
name "Supplier"
field :id, !types.ID
field :name, types.String
field :webpage, types.String
field :notes, types.String
field :errors, Types::JSONType
end
Types::SupplierInputType = GraphQL::InputObjectType.define do
name "SupplierInput"
argument :id, types.ID
argument :name, types.String
argument :webpage, types.String
argument :notes, types.String
end
and some custom types with `GraphQL::ScalarTypes` like
Types::DateType = GraphQL::ScalarType.define do
name "Date"
coerce_input ->(value, ctx) { Date.iso8601(value) }
coerce_result ->(value, ctx) { value.iso8601 }
end
## Queries
To keep schema definition clean use [`GraphQL::Function`](http://graphql-ruby.org/fields/function.html)
Types::QueryType = GraphQL::ObjectType.define do
name "Query"
field :supplier, function: Functions::FindById.new(Supplier)
field :allSuppliers, function: Functions::FindAll.new(Supplier) do
argument :filter, Types::SupplierFilterType
end
end
Above defines queries
fragment supplierFields on Supplier {
id
name
}
{
supplier(id: 1) {
...supplierFields
}
allSuppliers(offset: 1) {
...supplierFields
}
}
## Mutations
For mutations also use [`GraphQL::Function`](http://graphql-ruby.org/fields/function.html)
Types::MutationType = GraphQL::ObjectType.define do
name "Mutation"
field :createSupplier, function: Functions::Create.new(Supplier) do
argument :supplier, !Types::SupplierInputType
end
field :updateSupplier, function: Functions::Update.new(Supplier) do
argument :supplier, !Types::SupplierInputType
end
field :deleteSupplier, function: Functions::Delete.new(Supplier)
end
Try mutations (run one mutation at a time)
fragment supplierFields on Supplier {
id
name
}
mutation {
createSupplier(supplier: {name: "ACME"}) {
...supplierFields
errors
}
}
mutation {
updateSupplier(supplier: {id: 11, name: "NewCo"}) {
...supplierFields
errors
}
}
mutation {
deleteSupplier(id: 11) {
...supplierFields
}
}
We are using `Types::JSONType` to get validation `errors`, read more on [Error Handling](http://graphql-ruby.org/queries/error_handling.html)
## Relations
For one-to-one relations use `Functions::HasOne` that is wrapper around [exAspArk/batch-loader](https://github.com/exAspArk/batch-loader),
"Powerful tool to avoid N+1 DB or HTTP queries".
For one-to-many relations you can reuse `Functions::FindAll`.
Types::SupplierType = GraphQL::ObjectType.define do
name "Supplier"
#...
field :contact, function: Functions::HasOne.new('id', 'contactable_id', -> (ids, obj, args, ctx) {
Contact.where(contactable_id: ids, contactable_type: 'Supplier')
}) do
type Types::ContactType
end
field :products, function: Functions::FindAll.new(Product, -> (obj, args, ctx) {
obj.products
}) do
type types[Types::ProductType]
argument :filter, Types::ProductFilterType
end
end
## Server-side REST wrapper
You can use [`GraphQL::Function`](http://graphql-ruby.org/fields/function.html)
to write a [server-side REST wrapper](http://graphql.org/blog/rest-api-graphql-wrapper/).
Here is example for [Fixer.io](http://fixer.io/) "Foreign exchange rates and currency conversion API"
class Functions::CurrencyRates < GraphQL::Function
attr_reader :type
def initialize
@type = GraphQL::ObjectType.define do
name "CurrencyRates"
field :base, types.String
field :date, Types::DateType, resolve: ->(obj, args, ctx) { Date.iso8601(obj['date']) }
field :rates, Types::JSONType
end
end
argument :date, Types::DateType
argument :base, types.String, default_value: 'EUR'
def call(obj, args, ctx)
params = "#{args['date']||'latest'}?base=#{args['base']}"
response = HTTParty.get("http://api.fixer.io/#{params}", timeout: 10)
OpenStruct.new(response.parsed_response)
end
end
Query
{
currencyRates(date: "2017-10-02", base: "EUR") {
date
base
rates
}
}
## Tracking Schema with GraphQL IDL Schema Dump
To update GraphQL IDL Schema dump with rake task:
rake graphql:schema
See [Tracking Schema Changes With GraphQL-Ruby](http://rmosolgo.github.io/blog/2017/03/16/tracking-schema-changes-with-graphql-ruby/)
## TODO
- authorization
- testing
- file upload