Rails+GraphiQL을 사용하여 API 만들기

39873 단어 GraphQLRailsRubytech

각 버전


ruby: 2.7.1
rails: 6.0.3.4
graphql-ruby: 1.11.6

GraphQL Ruby


공식 페이지
Rails를 사용하여 GraphiQL을 처리할 때 ↑의gem을 사용하여 API를 설치합니다.

graphiql-rails


같이graphiql-railsgem를 미리 넣으면 브라우저에 설치된GraphQL의
IDE:sparkles:
graphql-ruby의 설치시 graphiql-rails의gem는 Gemfile에 추가
이미지

환경 구조


Gemfile
gem 'graphql'
gem 'graphiql-rails' # 今回は先に入れました
gem를 설치한 후 rails generate graphql:install 명령을 실행하여 파일을 생성합니다.
생성된 파일은 다음과 같다↓
$ rails generate graphql:install
      create  app/graphql/types
      create  app/graphql/types/.keep
      create  app/graphql/app_schema.rb
      create  app/graphql/types/base_object.rb
      create  app/graphql/types/base_argument.rb
      create  app/graphql/types/base_field.rb
      create  app/graphql/types/base_enum.rb
      create  app/graphql/types/base_input_object.rb
      create  app/graphql/types/base_interface.rb
      create  app/graphql/types/base_scalar.rb
      create  app/graphql/types/base_union.rb
      create  app/graphql/types/query_type.rb
add_root_type  query
      create  app/graphql/mutations
      create  app/graphql/mutations/.keep
      create  app/graphql/mutations/base_mutation.rb
      create  app/graphql/types/mutation_type.rb
add_root_type  mutation
      create  app/controllers/graphql_controller.rb
       route  post "/graphql", to: "graphql#execute"
     gemfile  graphiql-rails
       route  graphiql-rails
이때routes.rb는 다음과 같다.
Rails.application.routes.draw do

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

  post '/graphql', to: 'graphql#execute'
end

이루어지다


Query 만들기


먼저 테이블에 해당하는 Type을 정의해야 합니다.
예를 들어 다음과 같은users표에 대응하는user_type을 만들어 보고 싶습니다.
create_table :users do |t|
  t.string :name, null: false
  t.string :email
  t.timestamps
end
다음 명령을 실행하면 user_type가 생성됩니다.
(지정된 유형은 IDGraphiQL에서 정의한 id용 유형(실제 상황은 String)
또한 어미대!는 null을 허용하지 않는 유형이고, !는 null을 허용하지 않는 유형이다.)
$ bundle exec rails g graphql:object User id:ID! name:String! email:String
[보충] DB에 테이블이 있다면 잘 부탁드립니다.
$ bundle exec rails g graphql:object User
↑이래도 괜찮다:sparkles:
생성된 파일graphql/type/user_type.rb은 다음과 같습니다.
module Types
  class UserType < Types::BaseObject
    field :id, ID, null: false
    field :name, String, null: false
    field :email, String, null: true
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false
    field :updated_at, GraphQL::Types::ISO8601DateTime, null: false
  end
end
이미 생성된 graphql/type/query_type.rb에 다음과 같은 내용을 추가한다.
    field :users, [Types::UserType], null: false
    def users
      User.all
    end
http://localhost:3000/graphiql에 아래 조회를 던지면 답장이 있을 거라고 생각합니다.
{
  users {
    id
    name
    email
  }
}

Mutation 만들기


다음은 제작자의 뮤타ation스CreateUser를 만들고 싶다.
$ bundle exec rails g graphql:mutation CreateUser
graphql/mutations/create_user.rb가 만들어졌으며 다음과 같이 수정되었습니다.
module Mutations
  class CreateUser < BaseMutation
    field :user, Types::UserType, null: true

    argument :name, String, required: true
    argument :email, String, required: false

    def resolve(**args)
      user = User.create!(args)
      {
        user: user
      }
    end
  end
end
이미 생성된graphql/types/mutation_type.rb에 다음과 같은 내용을 보충한다.
module Types
  class MutationType < Types::BaseObject
    field :createUser, mutation: Mutations::CreateUser # 追記
  end
end
http://localhost:3000/graphiql에서 다음 작업을 수행하면 User가 생성됩니다.
mutation {
  createUser(
    input:{
      name: "user"
      email: "[email protected]"
    }
  ){
    user {
      id
      name 
      email
    }
  }
}

Association

  • 1:1의 관련표의 상황
  • 예로PostLabel1:1로 연관된 경우
    label_type.rb
    module Types
      class LabelType < Types::BaseObject
        field :id, ID, null: false
        field :name, String, null: false
        ...
      end
    end
    
    module Types
      class PostType < Types::BaseObject
        field :label, LabelType, null: true
      end
    end
    
    는 위에서 말한 바와 같이 labelLabelType로 정의할 수 있다.
    이 경우 Query 이미지로
    {
      posts {
        id
        label {
          id
          name
        }
      }
    }
    
    위에서 설명한 대로 labelLabelType에 필요한 값Query로 사용할 수 있습니다.
  • 1:N의 관련표의 상황
  • 예로UserPost와1:N의 경우
    module Types
      class PostType < Types::BaseObject
        field :id, ID, null: false
        field :label, LabelType, null: true
      end
    end
    
    module Types
      class UserType < Types::BaseObject
        field :posts, [PostType], null: false
      end
    end
    
    는 위에서 말한 바와 같이 posts[PostType]라고 정의하고Query로 할 수 있다.
    {
      user(id: 1234) {
        id
        posts {
          id
          label {
            id
            name
          }
        }
      }
    }
    
    위와 같이 호출할 수 있습니다.

    graphql-batch


    위에서 설명한 바와 같이 1:1과 1:N의 관련 표의 데이터도 가져올 수 있다
    이렇게 되면 DB에 문의가 쏟아질 수 있다.UserPost와 1:N의 경우Post가 100건이면 각각 100건의 문의가 발생한다.
    그럼 해결 방법 중 하나인 여러 상담graphql-batch을 소개해 드리겠습니다.
    gem 'graphql-batch'
    
    젬을 설치한 후 제작loader.loader는'다수의 자문을 종합하는'부분의 실현이다.
    graphql/loaders/record_loader.rb
    module Loaders
      class RecordLoader < GraphQL::Batch::Loader
        def initialize(model)
          @model = model
        end
    
        def perform(ids)
          @model.where(id: ids).each { |record| fulfill(record.id, record) }
          ids.each { |id| fulfill(id, nil) unless fulfilled?(id) }
        end
      end
    end
    
    이전 PostLabel 1:1로 연결된 경우
    module Types
      class PostType < Types::BaseObject
        field :label, LabelType, null: true
        def label
          Loaders::RecordLoader.for(Label).load(object.label_id)
        end
      end
    end
    
    이렇게 써도 돼요.UserPost와 1:N일 경우 로더를 별도로 제작한다.
    graphql/loaders/association_loader.rb
    module Loaders
      class AssociationLoader < GraphQL::Batch::Loader
        def self.validate(model, association_name)
          new(model, association_name)
          nil
        end
    
        def initialize(model, association_name)
          @model = model
          @association_name = association_name
          validate
        end
    
        def load(record)
          raise TypeError, "#{@model} loader can't load association for #{record.class}" unless record.is_a?(@model)
          return Promise.resolve(read_association(record)) if association_loaded?(record)
          super
        end
    
        # We want to load the associations on all records, even if they have the same id
        def cache_key(record)
          record.object_id
        end
    
        def perform(records)
          preload_association(records)
          records.each { |record| fulfill(record, read_association(record)) }
        end
    
        private
    
        def validate
          unless @model.reflect_on_association(@association_name)
            raise ArgumentError, "No association #{@association_name} on #{@model}"
          end
        end
    
        def preload_association(records)
          ::ActiveRecord::Associations::Preloader.new.preload(records, @association_name)
        end
    
        def read_association(record)
          record.public_send(@association_name)
        end
    
        def association_loaded?(record)
          record.association(@association_name).loaded?
        end
      end
    end
    
    ※ loader는graphiql-batch의 창고에 샘플이 있으니 이 샘플을 참고하여 설치할 수 있습니다
    다음과 같이 쓰면 통일적으로 묻는다.
    module Types
      class UserType < Types::BaseObject
        field :posts, [PostType], null: false
        def posts
          Loaders::AssociationLoader.for(User, :posts).load(object)
        end
      end
    end
    

    모드 파일에서 문서 생성


    마지막으로 정의된 패턴 파일에서 감각이 좋은 문서를 자동으로 만들어 보려고 합니다.routes.rb에 마운트할 수 있으며, 디버깅할 때마다graphidoc를 자동으로 업데이트합니다
    편리한gem를 찾을 때graphdoc-ruby라는gem가 있는데 한번 해 볼게요.Gemfile에 다음을 추가합니다.
    gem 'graphdoc-ruby'
    
    또한npm봉인@2fd/graphdoc이 필요합니다.
    Docker 이미지에 미리 설치합니다.(Docker를 사용하지 않으면 로컬 환경에 설치하면 됩니다.)
    예제)
    RUN set -ex \
        && wget -qO- https://deb.nodesource.com/setup_10.x | bash - \
        && apt-get update \
        && apt-get install -y \
                     ...
                     --no-install-recommends \
        && rm -rf /var/lib/apt/lists/* \
        && npm install -g yarn \
        && npm install -g @2fd/graphdoc # インストールしとく
    
    config/routes.rb에 다음과 같은 내용을 보충한다.
    config/routes.rb
    Rails.application.routes.draw do
      mount GraphdocRuby::Application, at: 'graphdoc'
    end
    
    ※ 노드 변경 시 수정config/initializers/graphdoc.rb예제)
    GraphdocRuby.configure do |config|
      config.endpoint = 'http://0.0.0.0:3000/api/v1/graphql'
    end
    
    Rails를 다시 시작하고 http://localhost:3000/graphdoc에 문서를 생성하면 OK:sparkles:

    방독 기술

  • http://localhost:3000/graphiql 액세스 시 다음 오류가 발생한 경우
    Sprockets::Rails::Helper::AssetNotPrecompiled in GraphiQL::Rails::Editors#show
    

  • 해결 방법 1app/assets/config/manifest.js에 다음을 추가합니다.
    //= link graphiql/rails/application.css
    //= link graphiql/rails/application.js
    
    AssetNotPrecompiled error with Sprockets 4.0 · Issue #75 · rmosolgo/graphiql-rails
    -> 이것만 있으면 Production 시Sprockets::FileNotFound: couldn't find file 'graphiql/rails/application.css'에 오류가 발생하여 사용할 수 없습니다...

  • 해결 방법 2 (순조로운 방법)gem 'sprocket'のバージョン3.7.2に下げる
    gem 'sprockets', '~> 3.7.2'  [#1098:  slowdev/knowledge/ios/FirebaseをCarthageで追加する](/posts/1098) 
    
    bundle update 추가
    Rails6의 API 모드에서 GraphiQL을 사용하는 방법(오류 대책 포함) - Qita

  • graphiql 화면에 표시TypeError: Cannot read property 'types' of undefined->손 옆 환경이라면 Rails를 재부팅하면 좋을 것 같아요.

  • graphiql 화면에 표시SyntaxError: Unexpected token < in JSON at position 0-> 오류가 발생할 수 있습니다. 로그를 보고 수정하십시오.
  • 참조 링크

  • 【Rails】graphiql-ruby로 API 만들기
  • REST API, 메인스트림(MainStream) 프로젝트에서 GraphiQL 가져오기 이야기(서버 전편) - SANBuilders Blog
  • "GraphiQL"의 철저한 입문-REST에 비해 API·프런트 쌍방의 실복 학습-엔지니어Hub|젊은 웹 엔지니어의 경력을 고려합니다!
  • GraphiQL을 사용하여 API Spec 센터 개발 및 그 효과에 대한 소개 - Kaizen Plaatform 개발자 블로그 가져오기
  • 지저분한 GraphiQL Ruby [class-based API] - Qita
  • Rubi(Sinatra) GraphiQL에서 시작하기
  • 기존 Rails 프로젝트에 GraphiQL API 추가
  • Rubby on Rails에서 sprockets에서 Webpacker로 이동, 옮길 수 없는 것들이 공존하는 방법 - Qiita
  • Reading: 첫 번째 GraphiQL-형의 기초 | tkhm | note
  • https://github.com/loopstudio/rails-graphql-api-boilerplate
  • https://github.com/rmosolgo/graphql-ruby-demo
  • 좋은 웹페이지 즐겨찾기