Skip to content

Instantly share code, notes, and snippets.

@phsym
Created March 28, 2018 14:12
Show Gist options
  • Save phsym/35dab9f880beab9c3afc1053e1d24d0a to your computer and use it in GitHub Desktop.
Save phsym/35dab9f880beab9c3afc1053e1d24d0a to your computer and use it in GitHub Desktop.
Coding-Corner 28-03-2018 : Introduction to GraphQL
require 'graphql'
require 'json'
require 'sinatra'
books = [
{id: 0, title: "A year at the wall", year: 2018, author: 0, themes:["mountains", "swords", "walkers"]},
{id: 1, title: "From basterd to king of the north", year: 2017, author: 0, themes: ["war", "king"]},
{id: 2, title: "Me and my dragons", year: 2017, author: 1, themes: ["dragons"]},
{id: 3, title: "I drink and I know things", year: 2017, author: 3, themes: ["rhum", "wine"]},
{id: 4, title: "How to get hated by the whole world", year: 2015, author: 4, themes: ["war", "king"]}
]
authors = [
{id: 0, firstname: "John", lastname: "Snow", friends: [1, 2, 3]},
{id: 1, firstname: "Daenerys", lastname: "Targaryen", friends: [0, 3]},
{id: 2, firstname: "Samwell", lastname: "Tarly", friends: [0]},
{id: 3, firstname: "Tyrion", lastname: "Lannister", friends: [0, 1]},
{id: 4, firstname: "Joffrey", lastname: "Baratheon", friends: []},
]
Author = GraphQL::ObjectType.define do
name "Author"
description "A book writer"
field :id, !types.Int, "The identification number", hash_key: :id
field :firstname, !types.String, "The firstname", hash_key: :firstname
field :lastname, !types.String, "The lastname", hash_key: :lastname
field :fullname, !types.String, "The fullname", resolve: ->(obj, _, _) {
obj[:firstname] + " " + obj[:lastname]
}
field :Friends, !types[!Author], "List of related authors", resolve: ->(obj, _, _) {
authors.select{|a| a[:friends].include?(obj[:id])}
}
field :Books, !types[!Book], "All the books written", resolve: ->(obj, _, _) {
books.select{|b| b[:author] == obj[:id]}
}
end
Book = GraphQL::ObjectType.define do
name "Book"
description "A book"
field :id, !types.Int, "The identification number", hash_key: :id
field :title, !types.String, "The book's title", hash_key: :title
field :year, !types.Int, "The year of publication", hash_key: :year
field :Author, !Author, "Get the book author", resolve: ->(obj, _, _) {authors[obj[:author]]}
end
QueryType = GraphQL::ObjectType.define do
field :Books, !types[!Book], "List all available books", resolve: ->(_, _, _){books}
field :Authors, !types[!Author], "List all known book writers", resolve: ->(_, _, _){authors}
field :themes, !types[!types.String], "List all book themes", resolve: ->(_, _, _) {
books.map{|b| b[:themes]}.reduce([]){|acc, themes| acc + themes}.uniq
}
field :BooksByTheme do
type !types[!Book]
description "Search a book by thematic"
argument :theme, !types.String, "The theme to look for"
resolve ->(_, args, _) {
books.select{|b| b[:themes].include?(args[:theme])}
}
end
field :BookById do
type Book
description "Search a book by its ID"
argument :id, !types.Int, "The ID to look for"
resolve ->(_, args, _) {books.find{|b| b[:id] == args[:id]}}
end
field :AuthorByName do
type Author
description "Search an author by its name"
argument :firstname, !types.String, "The firstname to look for"
argument :lastname, !types.String, "The lastname to look for"
resolve ->(_, args, _) {
authors.find{|a| a[:firstname] == args[:firstname] && a[:lastname] == args[:lastname]}
}
end
field :AuthorById do
type Author
description "Search an author by its ID"
argument :id, !types.Int, "The ID to look for"
resolve ->(_, args, _) {authors.find{|b| b[:id] == args[:id]}}
end
end
MutationType = GraphQL::ObjectType.define do
field :AddAuthor do
type !Author
argument :firstname, !types.String, "The author's firstname"
argument :lastname, !types.String, "The author's lastname"
resolve ->(_, args, _) {
author = (authors << {id: authors.size, firstname: args[:firstname], lastname: args[:lastname], friends: []}).last
# Schema.subscriptions.trigger("AuthorRegistered", {}, author)
author
}
end
end
# The root of the schema
Schema = GraphQL::Schema.define do
query QueryType
mutation MutationType
end
# Set the listenning port to 8080
set :port, (ENV['PORT'] || 8080).to_i
# Define graphql endpoints
post '/graphql' do
content_type :json
req = JSON.parse(request.body.read)
Schema.execute(req['query'], variables: req['variables'], context: {}).to_json
end
get '/graphql' do
content_type :json
Schema.execute(params['query'], variables: params['variables'], context: {}).to_json
end
get '/graphql/idl' do
content_type :text
Schema.to_definition
end
# REST interface equivalent
get '/authors' do
content_type :json
authors.to_json
end
get '/authors/:id' do
content_type :json
authors[params[:id].to_i].to_json
end
get '/authors/:id/books' do
content_type :json
books.select{|b| b[:author] == params[:id].to_i}.to_json
end
get '/authors/:id/friends' do
content_type :json
authors.select{|b| b[:friends].include?(params[:id].to_i)}.to_json
end
get '/books' do
content_type :json
return books.select{|b| b[:author] == params[:author].to_i}.to_json if params[:author]
return books.select{|b| b[:themes].include?(params[:theme])}.to_json if params[:theme]
return books.select{|b| b[:year] == params[:year].to_i}.to_json if params[:year]
books.to_json
end
get '/books/:id' do
content_type :json
books[params[:id].to_i].to_json
end
get '/books/:id/author' do
content_type :json
authors.select{|a| a[:id] == books[params[:id].to_i][:author]}.to_json
end
@phsym
Copy link
Author

phsym commented Mar 28, 2018

This is an all in one ruby file definning both graphql and rest interfaces shown during the presentation.

The web GUI code is not part of this (have a look at GraphiQL for more datails)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment