Upgrade to Pro — share decks privately, control downloads, hide ads and more …

GraphQL for Rubyists

GraphQL for Rubyists

The accompanying recording of this presentation is available here: http://rubythursday.com/talks/ruby-roundtable-graphql-relay.

Brooks Swinnerton

June 04, 2016
Tweet

More Decks by Brooks Swinnerton

Other Decks in Technology

Transcript

  1. { "kind": "Listing", "data": { "modhash": "", "children": [ {

    "kind": "t3", "data": { "id": "4lyzb1", "created": 1464776494, "title": "Cat.", "author": "AcezennJames", "score": 1, "num_comments": 0, "subreddit": "CatsStandingUp", "url": "https://i.reddituploads.com/da4620368fdd4c08a17e3b2f56571889? fit=max&h=1536&w=1536&s=a7a58b1ca15529fa6dda138d12d6fb51", "permalink": "/r/CatsStandingUp/comments/4lyzb1/cat/", "thumbnail": "http://b.thumbs.redditmedia.com/uT4-uPd2Z7Jt-gVdJSswq8W5bTa9Jchfnb3GHRlhHLE.jpg", "locked": false } } ] } }
  2. require 'net/http' require 'json' uri = URI('https://api.reddit.com/r/catsstandingup.json') response = Net::HTTP.get(uri)

    parsed_response = JSON.parse(response) posts = parsed_response['data']['children'] html = posts.each_with_object('') do |post, string| thumbnail = post['data']['thumbnail'] string << "<img src='#{thumbnail}' />" end File.write('cats_standing_up.html', html)
  3. { "kind": "Listing", "data": { "modhash": "", "children": [ {

    "kind": "t3", "data": { "id": "4lyzb1", "created": 1464776494, "title": "Cat.", "author": "AcezennJames", "score": 1, "num_comments": 0, "subreddit": "CatsStandingUp", "url": "https://i.reddituploads.com/da4620368fdd4c08a17e3b2f56571889? fit=max&amp;h=1536&amp;w=1536&amp;s=a7a58b1ca15529fa6dda138d12d6fb51", "permalink": "/r/CatsStandingUp/comments/4lyzb1/cat/", "thumbnail": "http://b.thumbs.redditmedia.com/uT4-uPd2Z7Jt-gVdJSswq8W5bTa9Jchfnb3GHRlhHLE.jpg", "locked": false } } ] } }
  4. { me { firstName lastName email } } { "data":{

    "me":{ "firstName":"Brooks", "lastName":"Swinnerton", "email":"[email protected]" } } }
  5. { restaurant(name: "Cafe Ghia") { name buildingNumber street zipcode borough

    grade } } { "data": { "restaurant": { "name": "Cafe Ghia", "buildingNumber": "24", "street": "Irving Avenue", "zipcode": "11237", "borough": "BROOKLYN", "grade": "A" } } } https://nyc-restaurant-grades.com/graphql POST
  6. ActiveRecord::Schema.define(version: 20160605211006) do create_table "inspections"do |t| t.integer "restaurant_id" t.text "type"

    t.datetime "inspected_at" t.datetime "graded_at" t.integer "score" t.text "violation_description" t.text "violation_code" t.text "grade" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "restaurants"do |t| t.text "name" t.text "camis" t.text "building_number" t.text "street" t.text "zipcode" t.integer "borough" t.text "cuisine" t.datetime "created_at", null: false t.datetime "updated_at", null: false end end db/schema.rb
  7. class Restaurant < ActiveRecord::Base enum borough: ['BRONX', 'BROOKLYN', 'MANHATTAN', 'STATEN_ISLAND',

    'QUEENS'] has_many :inspections def grade return unless last_inspection last_inspection.grade end private def last_inspection inspections.where.not(grade: nil).order(inspected_at: :desc).last end end app/models/restaurant.rb
  8. app/graph/graph/types/restaurant.rb module Graph module Types Restaurant = GraphQL::ObjectType.define do name

    'Restaurant' description 'A place of business serving food in New York City' global_id_field :id field :name, !types.String, 'The doing-business-as value.' field :camis, !types.String, 'The unique identifier.' field :buildingNumber, types.String, 'The street number.', property: :building_number field :street, types.String, 'The street name.' field :zipcode, types.String, 'The zip code.' field :cuisine, types.String, 'The cuisine.' field :grade, types.String, 'The latest grade of an inspection.' end end end
  9. app/graph/graph/types/inspection.rb module Graph module Types Inspection = GraphQL::ObjectType.define do name

    'Inspection' description 'A NYC health inspection.' global_id_field :id field :type, types.String, 'The type of inspection.' field :violationDescription, types.String, 'The violation description.', property: :violation_description field :violationCode, types.String, 'The violation code cited.', property: :violation_code field :grade, types.String, 'The grade received.' field :score, types.Int, 'The numeric score received.' field :inspectedAt, !types.String, 'The inspection timestamp.', property: :inspected_at field :gradedAt, types.String, 'The issued grade timestamp.', property: :graded_at end end end
  10. app/graph/graph/types/root_query.rb module Graph module Types RootQuery = GraphQL::ObjectType.define do name

    "RootQuery" description "The query root." field :restaurant do type -> { Types::Restaurant } description "Perform a search for one restaurant." argument :name, types.String resolve -> (object, arguments, context) do ::Restaurant.find_by(name: arguments['name']) end end end end end
  11. { restaurant(name: "Cafe Ghia") { name buildingNumber street zipcode borough

    grade } } { "data": { "restaurant": { "name": "Cafe Ghia", "buildingNumber": "24", "street": "Irving Avenue", "zipcode": "11237", "borough": "BROOKLYN", "grade": "A" } } } https://nyc-restaurant-grades.com/graphql POST
  12. class Restaurant < ActiveRecord::Base enum borough: ['BRONX', 'BROOKLYN', 'MANHATTAN', 'STATEN_ISLAND',

    'QUEENS'] has_many :inspections def grade return unless last_inspection last_inspection.grade end private def last_inspection inspections.where.not(grade: nil).order(inspected_at: :desc).last end end app/models/restaurant.rb
  13. { "name": "Cafe Ghia", "buildingNumber": "24", "street": "Irving Avenue", "zipcode":

    "11237", "borough": "BROOKLYN" } { "grade": "A", "score": 13, "type": "Cycle Inspection", "violationCode": "10B", "violationDescription": "Plumbing not properly installed.", "inspectedAt": "2016-02-18 00:00:00 UTC", "gradedAt": "2016-02-18 00:00:00 UTC" }
  14. { "name": "Cafe Ghia", "buildingNumber": "24", "street": "Irving Avenue", "zipcode":

    "11237", "borough": "BROOKLYN" } { "grade": "A", "score": 13, "type": "Cycle Inspection", "violationCode": "02G", "violationDescription": "Cold food item held above 41ºF", "inspectedAt": "2016-02-18 00:00:00 UTC", "gradedAt": "2016-02-18 00:00:00 UTC" } { "grade": "A", "score": 13, "type": "Cycle Inspection", "violationCode": "10B", "violationDescription": "Plumbing not properly installed.", "inspectedAt": "2016-02-18 00:00:00 UTC", "gradedAt": "2016-02-18 00:00:00 UTC" }
  15. { restaurant(name:"Cafe Ghia") { inspections(first:2) { edges { node {

    violationCode violationDescription } } } } } https://nyc-restaurant-grades.com/graphql POST
  16. { restaurant(name:"Cafe Ghia") { inspections(first:2) { edges { node {

    violationCode violationDescription } } } } } { "data": { "restaurant": { "inspections": { "edges": [ { "node": { "violationCode": "10F", "violationDescription": "Non-food contact surface improperly constructed. Unacceptable material used." } }, { "node": { "violationCode": "04L", "violationDescription": "Evidence of mice or live mice present in facility's food and/or non-food areas." } } ] } } } } https://nyc-restaurant-grades.com/graphql POST
  17. app/graph/graph/types/restaurant.rb module Graph module Types Restaurant = GraphQL::ObjectType.define do name

    'Restaurant' description 'A place of business serving food in New York City' connection :inspections, -> { Types::Inspection.connection_type } do description 'List the inspections.' resolve -> (object, arguments, context) do object.inspections end end end end end