Ruby on Rails의 GraphQL 다중 스키마 생성
GraphQL은 스키마를 분리하기 위한 동기를 부여하고 자동 재귀를 필요로 하며 자동으로 종료해야 합니다. 필요한 경우 별도의 os 스키마가 필요한 경우 응용 프로그램을 실행하기 위해 응용 프로그램을 실행하고 시스템 내부 관리를 실행해야 합니다. Assim, seus schemas entregam apenas o que é necessário para aplicação que irá consumir e também restringe o acesso de recursos internos.
손에!
Todo o código fonte pode ser encontrado aqui
Neste example, vamos fazer uma API de um blog, mas para manter a simplicidade, vamos ignorar a parte de autenticação.
Teremos dois 스키마.
Após criar a plicação, install a gem graphql e executar o comando
rails generate graphql:install
, teremos a seguinte estrutura de arquivos.app
├── controllers
│ ├── application_controller.rb
│ └── graphql_controller.rb
└── graphql
├── app_name_schema.rb
├── mutations
│ └── base_mutation.rb
└── types
├── base_argument.rb
├── base_connection.rb
├── base_edge.rb
├── base_enum.rb
├── base_field.rb
├── base_input_object.rb
├── base_interface.rb
├── base_object.rb
├── base_scalar.rb
├── base_union.rb
├── mutation_type.rb
├── node_type.rb
└── query_type.rb
네임스페이스, 쿼리, 뮤테이션, 유형과 같은 파스타 그래프를 정확히 살펴보세요.
Veja como é o schema inicial gerado pelo installador.
# app/graphql/app_name_schema.rb
class AppNameSchema < GraphQL::Schema
mutation(Types::MutationType)
query(Types::QueryType)
end
Um 스키마는 돌연변이로 기본 클래스를 구성하고 클래스는 쿼리로 쿼리를 정의합니다.
Veja como é o controller inicial gerado pelo installador.
class GraphqlController < ApplicationController
protect_from_forgery with: :null_session
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
# Query context goes here, for example:
# current_user: current_user,
}
result = AppNameSchema.execute(query, variables: variables, context: context, operation_name: operation_name)
render json: result
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# Handle variables in form data, JSON body, or a blank value
def prepare_variables(variables_param)
case variables_param
when String
if variables_param.present?
JSON.parse(variables_param) || {}
else
{}
end
when Hash
variables_param
when ActionController::Parameters
variables_param.to_unsafe_hash # GraphQL-Ruby will validate name and type of incoming variables.
when nil
{}
else
raise ArgumentError, "Unexpected parameter: #{variables_param}"
end
end
def handle_error_in_development(e)
logger.error e.message
logger.error e.backtrace.join("\n")
render json: { errors: [{ message: e.message, backtrace: e.backtrace }], data: {} }, status: 500
end
end
Precisaremos definir dois endpoints graphql, um para o schema público e outro para o schema privado.
Mas primeiro, vamos gerar os models que usaremos na aplicação.
rails g model author name
rails g model post title content:text author:references
rails g model email email
O 모델은 이메일을 통해 게시물을 수신하거나 공개적으로 사용하는 방법을 사용합니다.
Vamos는 pelo graphql público를 제공합니다. Vamos ter 1
query
que lista os posts, 1 query
que retorna um post pelo ID e uma mutation
que cadastra o email na lista de emails.파스타 두 graphql público fica assim.
# app/graphql/public_graphql.rb
class PublicGraphql < GraphQL::Schema
mutation(Mutations)
query(Queries)
end
# app/graphql/public_graphql/mutations.rb
class PublicGraphql
class Mutations < Types::BaseObject
field :add_email_to_list, mutation: AddEmailToList
end
end
# app/graphql/public_graphql/queries.rb
class PublicGraphql
class Queries < Types::BaseObject
include Posts
include PostById
end
end
Acima já descrevi as query e mutations que teremos, elas ficarão dentro dos namespaces Queries e Mutations.
쿼리와 같은 seguir.
# app/graphql/public_graphql/queries/posts.rb
class PublicGraphql
class Queries
module Posts
extend ActiveSupport::Concern
included do
field :posts, [Types::Post], null: false
end
def posts
Post.all
end
end
end
end
# app/graphql/public_graphql/queries/post_by_id.rb
class PublicGraphql
class Queries
module PostById
extend ActiveSupport::Concern
included do
field :post_by_id, Types::Post, null: true do
argument :id, GraphQL::Types::ID, required: true
end
end
def post_by_id(id:)
Post.find_by(id:)
end
end
end
end
Para que as query funcionem, precisamos dos types que utilizamos nelas, que é apenas o
Post
.# app/graphql/types/post.rb
module Types
class Post < Types::BaseObject
field :id, ID, null: false
field :title, String, null: false
field :content, String, null: false
field :author, Types::Author, null: false
end
end
# app/graphql/types/author.rb
module Types
class Author < Types::BaseObject
field :id, ID, null: false
field :name, String, null: false
end
end
참고 que colocamos os 유형 na 파스타 raiz 유형 mesmo. Fiz isso pois precisamos desses tipos no graphql privado também, então aqui fica compartilhado. 특정 스키마에 대한 특정 스키마를 사용하는 경우 PublicGraphql 메모 공간에서 네임스페이스를 사용할 수 있습니다.
Já as mutations, movi a classe
Mutations::BaseMutation
(essa é a que foi gerada automaticamente pela gem) para Types::BaseMutation
. 돌연변이 파스타를 제외하고 파스타를 만드십시오.돌연변이 AddEmailToList fica assim:
# app/graphql/public_graphql/mutations/add_email_to_list.rb
class PublicGraphql
class Mutations
class AddEmailToList < Types::BaseMutation
argument :email, String, required: true
field :success, Boolean, null: false
def resolve(email:)
{ success: !!Email.create(email:) }
end
end
end
end
Para finalizar o Graphql público, falta seu controller. Assim, PublicGraphqlController의 크리아모스
# app/controllers/public_graphql_controller
class PublicGraphqlController < ApplicationController
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
result = PublicGraphql.execute(query, variables:, operation_name:) # here we call the PublicGraphql class
render json: result
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# same private methods from the generated class
end
Não esqueça de atualizar as rotas
Rails.application.routes.draw do
post "/graphql", to: "public_graphql#execute"
# ...
end
O PrivateGraphql podemos seguir o mesmo estilo. Aqui vamos ter a listagem de posts de um autor e o cadastro de posts.
# app/graphql/private_graphql.rb
class PrivateGraphql < GraphQL::Schema
mutation(Mutations)
query(Queries)
end
# app/graphql/private_graphql/queries.rb
class PrivateGraphql
class Queries < Types::BaseObject
include MyPosts
end
end
# app/graphql/private_graphql/mutations.rb
class PrivateGraphql
class Mutations < Types::BaseObject
field :create_post, mutation: CreatePost
end
end
# app/graphql/private_graphql/queries/my_posts.rb
class PrivateGraphql
class Queries
module MyPosts
extend ActiveSupport::Concern
included do
field :my_posts, [Types::Post], null: false
end
def my_posts
context[:current_author].posts
end
end
end
end
# app/graphql/private_graphql/mutations/create_post.rb
class PrivateGraphql
class Mutations
class CreatePost < Types::BaseMutation
argument :title, String, required: true
argument :content, String, required: true
field :post, Types::Post, null: false
def resolve(title:, content:)
post = Post.new(title:, content:, author: context[:current_author])
if post.save
{post:}
else
{}
end
end
end
end
end
# app/controllers/private_graphql_controller.rb
class PrivateGraphqlController < ApplicationController
# here you can put an authentication method to protect your private graphql schema
# before_action :authenticate!
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = { current_author: Author.first } # hardcoding an author just for example
result = PrivateGraphql.execute(query, variables:, context:, operation_name:)
render json: result
rescue StandardError => e
raise e unless Rails.env.development?
handle_error_in_development(e)
end
private
# same private methods from the generated class
end
# config/routes.rb
Rails.application.routes.draw do
# ...
post "/private_graphql", to: "private_graphql#execute" # added
end
빨리! Temos dois schemas bem separados e organizados.
Nossa nova estrutura ficou da seguinte forma.
├── private_graphql
│ ├── mutations
│ │ └── create_post.rb
│ ├── mutations.rb
│ ├── queries
│ │ └── my_posts.rb
│ └── queries.rb
├── private_graphql.rb
├── public_graphql
│ ├── mutations
│ │ └── add_email_to_list.rb
│ ├── mutations.rb
│ ├── queries
│ │ ├── post_by_id.rb
│ │ └── posts.rb
│ └── queries.rb
├── public_graphql.rb
└── types
├── author.rb
├── base_argument.rb
├── base_connection.rb
├── base_edge.rb
├── base_enum.rb
├── base_field.rb
├── base_input_object.rb
├── base_interface.rb
├── base_mutation.rb
├── base_object.rb
├── base_scalar.rb
├── base_union.rb
├── mutation_type.rb
├── node_type.rb
├── post.rb
└── query_type.rb
Nessa organização fica simples encontrar onde cada operação está e só de bater o olho na 파스타 você consegue ver tudo o que aquela API expõe.
Vale notar também que separar cada query e cada mutation em um único arquivo também ajuda na hora dos testes, pois eles ficam mais concisos!
조직이 필요합니까? 여러 조직 스키마 graphql에 대해 어떻게 생각하십니까? Deixa teu 코멘트 abaixo :) !
Reference
이 문제에 관하여(Ruby on Rails의 GraphQL 다중 스키마 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/mtayllan/gerenciando-multiplos-schemas-de-graphql-com-ruby-on-rails-2kge텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)