LoginSignup
9
2

More than 1 year has passed since last update.

GraphQLでRailsのスキーマからフロント(TS, urql)の型生成までできるようにしてみた

Last updated at Posted at 2022-12-15

GraphQLとは何か

GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

GraphQLは、APIのクエリ言語であり、既存のデータを使用してこれらのクエリを実行するためのランタイムです。GraphQLは、API内のデータの完全でわかりやすい説明を提供し、クライアントが必要なものだけを正確に要求できるようにし、時間をかけてAPIを進化させやすくし、強力な開発者ツールを有効にします。
引用: https://graphql.org/

要するに、クエリ言語でAPIのドキュメント、問い合わせを定義することで我々が開発しているAPIの変更を容易にしてくれるものです

GraphQLでできる事

  • graphqlドキュメントを介してフロント・バック間の分業がしやすくなる
  • バックエンド
    • DBのスキーマからgraphqlのAPI定義(ドキュメント)を自動生成できる
  • フロントエンド
    • バックエンドで自動生成したドキュメントからさらに自動で型生成することができる

スキーマ変更を伴う改修をした時の実装コストが下がる!!(かもしれない

ハンズオン

ユーザーを取得するAPIを実装するケースを考えます

バックエンド

登場人物

  • graphql-ruby
  • graphiql-rails

前提として、graphqlのAPI開発に必要なファイル群を自動生成します

rails g graphql:install

実際のAPI開発に進みます。今回はUserを取得するエンドポイントを考えます

まず User の オブジェクトを生成します

rails g graphql:object User

するとusersテーブルのスキーマからGraphQL Type相当のコードが自動生成されます。

生成されたコードを見る
.ruby
# frozen_string_literal: true

module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :email, String, null: false
    # こういう露出したくないフィールドは削る 
    # field :crypted_password, String
    # field :salt, String
    field :is_verified, Boolean, null: false
    field :deleted_at, GraphQL::Types::ISO8601DateTime
    field :name_sei, String, null: false
    field :name_mid, String, null: false
    field :name_mei, String, null: false
		...
    # associationは自分で追加してあげる必要がある(要N+1対策
    field :activities, [Types::ActivitiyType], null: false
  end
end

graphql/query_type.rb でエンドポイントを定義します

.ruby
field :users, [Types::UserType], null: false do
  description '全ユーザー返す'
end

def users
  User.all
end

次に graphql スキーマを吐かせないといけないのですが、標準でそのような rakeタスクは用意されていないので、自分で作る必要があります。

lib/tasks/graphql.rake
require "graphql/rake_task"
GraphQL::RakeTask.new(schema_name: "MySchema")

このrakeタスクを作成してから

$ rails graphql:schema:idl

を叩くと graphqlドキュメントが生成されます

こちら
type Query {
  """
  全てユーザー返す
  """
  users: [User!]!
}

type User {
  createdAt: ISO8601DateTime!
  deletedAt: ISO8601DateTime
  email: String!
  id: ID!
  nameSei: String!
  nameMid: String!
  nameMei: String!
  updatedAt: ISO8601DateTime!
  ...
}
APIはこれで OK

フロントエンド

登場人物

  • urql
  • graphql-codegen

まずはクエリを定義します。

export const UsersQuery = graphql(/* GraphQL query */ `
  query UserQuery {
    users {
      id,
      email,
      nameSei,
      nameMid,
      nameMei
    }
  }
`);

次にgraphqlの設定ファイルを置きます

codegen.ts
import type { CodegenConfig } from '@graphql-codegen/cli'

const config: CodegenConfig = {
   schema: './schema.graphql',
   documents: ['src/**/*.{ts,tsx}'],
   generates: {
      './src/graphql': {
        preset: 'client',
        plugins: []
      }
   }
}
export default config

これで

$ yarn graphql-codegen

すると型が自動生成されます。(自動生成された型は膨大なので割愛

実際に urql で呼び出すといい感じに型がついています
%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88_2022-10-26_15.24.36.png

N+1対策

本筋とは逸れますが、railsでgraphqlを使う場合、includes preloadしてもはN+1が起きてしまいます。
そこで、graphql-batchというライブラリを利用することでN+1を回避することができます。
以下の記事がとても参考になったので供養

参照

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2