rails graphql的使用

樓上有隻喵發表於2020-10-29

1.graphql的基本概念

  • GraphQL 是一種針對 Graph(圖狀資料)進行查詢特別有優勢的 Query Language(查詢語言),所以叫做 GraphQL。
  • 它跟 SQL 的關係是共用 QL 字尾,就好像「漢語」和「英語」共用字尾一樣,但他們本質上是不同的語言。
  • GraphQL 並沒有和任何特定資料庫或者儲存引擎繫結,而是依靠你現有的程式碼和資料支撐。
  • 向你的 API 發出一個 GraphQL 請求就能準確獲得你想要的資料,不多不少

2.graphql的組成部分

  • Fields: 是關於請求物件上的特定欄位
  • Arguments:請求時傳遞的引數以及它們是什麼物件型別, 這是必需的。這有點類似於在Rails控制器中定義強引數,這裡對進入的內容進行更細粒度的控制。
  • Types: 型別,用於定義資料型別,或者定義Rails模型model,型別包括根據-Queries/Mutations中的請求相應資料的欄位和函式。型別也可以是靜態的,比如:String或ID,這些內建在伺服器端的library中。
  • Queries:從API獲取特定的資料。將查詢設定為只讀,就像Rest裡面的Get,但是查詢不僅是Get。
  • Mutations: 變更,對API資料的修改,比如:create、update、destroy。
  • Resolver解析器:resolve方法是執行ActiveRecord命令的地方。他返回一個帶有和上面定義的欄位名稱一樣的鍵的hash.
  • Functions: 方法、功能,給上面的欄位提供資料,

3.建立一個基於graphql的rails專案

step1:建立一個rails 專案,並生成對應的model**

  • rails new graphql_fun_demo
  • rails g model User email:string name:string
  • rails g model Post user:belongs_to title:string body:text
  • rails db:migrate

step2: 引入gem包

  • gem ‘faker’
  • gem ‘graphiql-rails’

step3:在user.rb裡面加入 has_many :books

在seeds.rb檔案,通過faker建立一些資料

5.times do
  user = User.create(name: Faker::Name.name, email: Faker::Internet.email)
  5.times do
    user.posts.create(title: Faker::Lorem.sentence(word_count: 3),
                     body: Faker::Lorem.paragraph(sentence_count: 3))
  end
end

step4: 建立graphql目錄和2個新的自定義型別User和Post

  • rails g graphql:install
  • rails g graphql:object user
  • rails g graphql:object post

step5: 在routes.rb中,建立app/controllers/graphql_controller.rb#execute,作為api訪問的入口

 if Rails.env.development?
    mount GraphiQL::Rails::Engine, at: '/graphql', graphql_path:"graphql#execute"
  end

啟動專案,訪問http://localhost:3000/graphiql,就可以看到測試api介面的頁面

step6: 建立GraphQL的型別(Type)

module Types
  class UserType < Types::BaseObject
    # null: false 不允許為空
    field :id, ID, null: false
    field :name, String, null: true
    field :email, String, null: true
    field :posts, Types::PostType, null: true
    field :posts_count, Integer, null: true

    def posts_count
      object.posts.size
    end
  end
end
module Types
  class PostType < Types::BaseObject
    field :id, ID, null: false
    field :user_id, Integer, null: true
    field :title, String, null: true
    field :body, String, null: true
  end
end

step7: 定義主查詢型別

query_type.rb和mutation_type.rb這兩種傳入請求的路由,定義在模式schema裡面,他們和Rails路由和資源有些相似。分別為查詢和修改特定的資料

    class GraphqlApiSchema < GraphQL::Schema
      mutation(Types::MutationType)
      query(Types::QueryType)
    end

step8: 在query_type檔案裡面,定義:users和:user的欄位,以及他們的方法

module Types
  class QueryType < Types::BaseObject
    field :users, [Types::UserType], null: false

    # users方法返回UserType型別的一組物件。
    def users
      User.all
    end

    # user方法接收一個型別為ID的:id的引數,返回一個UserType物件,(ID是一個內建的型別)
    field :user, Types::UserType, null: false do
      argument :id, ID, required: true
    end

    def user(id:)
      User.find(id)
    end
  end
end

step9: 測試查詢

  • 查詢所有使用者資訊
query{
  users{
    id
    name
    email
    postsCount
  }
}
  • 查詢指定id的使用者資訊
 query{
  user(id:2){
    id
    name
    email
    postsCount
  }
}

step10: Mutations(變更 )

Mutations允許建立、修改、銷燬資料,我們設定一個基類,用來擴充套件CreateUser的mutation。

module Mutations
  class BaseMutation < GraphQL::Schema::RelayClassicMutation
  end
end

step11: 建立CreateUser的mutation。

class Mutations::CreateUser < Mutations::BaseMutation
  argument :name, String, required: true
  argument :email, String, required: true

  # 和上面查詢欄位概念相同,接收引數建立物件,同時希望返回一個user帶有我們的新模型的欄位,並附帶一個errors陣列。
  field :user, Types::UserType, null: false
  field :errors, [String], null: false

  def resolve(name:, email:)
    user = User.new(name: name, email: email)
    if user.save
      {
        user: user,
        errors: [],
      }
    else
      {
        user: nil,
        errors: user.errors.full_message
      }
    end
  end
end

step12: 將新變更mutation新增到主突變型別類中,以便暴露給我們的API。

module Types
  class MutationType < Types::BaseObject
    field :create_user, mutation: Mutations::CreateUser
  end
end

step13 建立使用者測試

我們傳入一個createUser(input: {})物件; 這對映到:create_user接受單個input引數的欄位。

mutation{
  createUser(input:{
    name:"張三",
    email:"aa@qq.com"
  }){
    user{
      id
      name
      email
    }
    errors
  }
}

相關文章