graphql-рубиновый. Используйте (не реле) мутации СУХОЙ. С или без GraphQL::Function?

Я НЕ ИСПОЛЬЗУЮ РЕЛЕ.

Я прочитал несколько уроков. Многие используют этот способ для мутаций:

Приложение /graphql/graphql_tutorial_schema.rb

GraphqlTutorialSchema = GraphQL::Schema.define do
  query(Types::QueryType)
  mutation(Types::MutationType)
end

приложение / graphql / резольверы /create_link.rb

class Resolvers::CreateLink < GraphQL::Function
  argument :description, !types.String
  argument :url, !types.String

  type Types::LinkType

  def call(_obj, args, _ctx)
    Link.create!(
      description: args[:description],
      url: args[:url],
    )
  end
end

и наконец они имеют:

Приложение / graphql / типы /mutation_type.rb

Types::MutationType = GraphQL::ObjectType.define do
  name 'Mutation'

  field :createLink, function: Resolvers::CreateLink.new
end

Таким образом, они используют GraphQL::Function,

Это путь? Если я не использую ретранслятор, это единственный путь?

А что, если я хочу уникальный файл для всех link операции (CRUD)?

Другие руководства ( http://tech.eshaiju.in/blog/2017/05/15/graphql-mutation-query-implementation-ruby-on-rails/) используют это:

Приложение / graphql / мутации /comment_mutations.rb

module CommentMutations
  Create = GraphQL::Relay::Mutation.define do
    name "AddComment"

    # Define input parameters
    input_field :articleId, !types.ID
    input_field :userId, !types.ID
    input_field :comment, !types.String

    # Define return parameters
    return_field :article, ArticleType
    return_field :errors, types.String

    resolve ->(object, inputs, ctx) {
      article = Article.find_by_id(inputs[:articleId])
      return { errors: 'Article not found' } if article.nil?

      comments = article.comments
      new_comment = comments.build(user_id: inputs[:userId], comment: inputs[:comment])
      if new_comment.save
        { article: article }
      else
        { errors: new_comment.errors.to_a }
      end
    }
  end
end

и app/graphql/mutations/mutation_type.rb

MutationType = GraphQL::ObjectType.define do
  name "Mutation"
  # Add the mutation's derived field to the mutation type
  field :addComment, field: CommentMutations::Create.field
end

поэтому я могу добавить также:

MutationType = GraphQL::ObjectType.define do
  name "Mutation"
  field :addComment, field: CommentMutations::Create.field
  field :updateComment, field: CommentMutations::Update.field
  field :deleteComment, field: CommentMutations::Delete.field
end

Но это хорошо работает только с Create = GraphQL::Relay::Mutation.define: Я не использую реле!

В ваших документах я не нашел ничего, связанного с этой проблемой.

Я должен всегда использовать GraphQL:: Функции?

Или, может быть, я могу использовать это так:

MutationType = GraphQL::ObjectType.define do
  name "Mutation"
  field :addComment, field: CommentMutations::Create
  field :updateComment, field: CommentMutations::Update
  field :deleteComment, field: CommentMutations::Delete
end

и иметь это (код является примером):

module Mutations::commentMutations
  Createcomment = GraphQL::ObjectType.define do
    name "Createcomment"

    input_field :author_id, !types.ID
    input_field :post_id, !types.ID

    return_field :comment, Types::commentType
    return_field :errors, types.String

    resolve ->(obj, inputs, ctx) {
      comment = comment.new(
        author_id: inputs[:author_id],
        post_id: inputs[:post_id]
      )

      if comment.save
        { comment: comment }
      else
        { errors: comment.errors.to_a }
      end
    }
  end

Updatecomment = GraphQL::ObjectType.define do
    name "Updatecomment"

    input_field :author_id, !types.ID
    input_field :post_id, !types.ID

    return_field :comment, Types::commentType
    return_field :errors, types.String

    resolve ->(obj, inputs, ctx) {
      comment = comment.new(
        author_id: inputs[:author_id],
        post_id: inputs[:post_id]
      )

      if comment.update
        { comment: comment }
      else
        { errors: comment.errors.to_a }
      end
    }
  end
end

Это другой способ?

2 ответа

Вам следует попробовать https://github.com/samesystem/graphql_rails gem. Он имеет структуру MVC на стороне graphql, поэтому ваш GraphQL будет почти таким же, как ваш код RoR.

А что, если мне нужен уникальный файл для всех операций со ссылками (CRUD)?

В GraphqlRails вместо преобразователей есть контроллеры. У вас могло быть что-то вроде этого:

class CommentsController < GraphqlRails::Controller
  action(:create).permit(:article_id, :body).returns(!Types::CommentType)
  action(:update).permit(:id, :body).returns(!Types::CommentType)

  def create
    Comment.create!(params)
  end

  def update
    Comment.find(params[:id]).update!(params)
  end
end

Вот как сейчас выглядит моя:

blah_schema.rb

BlahSchema = GraphQL::Schema.define do
  ...
  query(Types::QueryType)

mutation_type.rb

Types::MutationType = GraphQL::ObjectType.define do
  name "Mutation"


  field :comment, !Types::CommentType do
    argument :resource_type, !types.String
    argument :resource_id,  !types.ID
    argument :comment, !types.String

    resolve ResolverErrorHandler.new ->(obj, args, ctx) do
      ctx[:current_user].comments.
        create!(resource_id: args[:resource_id],
          resource_type: args[:resource_type],
          comment: args[:comment])
    end
  end

  field :destroy_comment, !Types::CommentType do
    argument :id, !types.ID
    resolve ResolverErrorHandler.new ->(obj, args, ctx) do
      comment = ctx[:current_user].comments.where(id: args[:id]).first
      if !comment
        raise ActiveRecord::RecordNotFound.new(
          "couldn't find comment for id #{args[:id]} belonging to #{current_user.id}")
      end

      comment.destroy!
      comment
    end
  end
end

resolver_error_handler.rb

class ResolverErrorHandler

  def initialize(resolver)
    @r = resolver
  end

  def call(obj, args, ctx)
    @r.call(obj, args, ctx)
  rescue ActiveRecord::RecordNotFound => e
    GraphQL::ExecutionError.new("Missing Record: #{e.message}")
  rescue AuthorizationError => e
    GraphQL::ExecutionError.new("sign in required")
  rescue ActiveRecord::RecordInvalid => e
    # return a GraphQL error with validation details
    messages = e.record.errors.full_messages.join("\n")
    GraphQL::ExecutionError.new("Validation failed: #{messages}")
  rescue StandardError => e
    # handle all other errors
    Rails.logger.error "graphql exception caught: #{e} \n#{e.backtrace.join("\n")}"
    Raven.capture_exception(e)

    GraphQL::ExecutionError.new("Unexpected error!")
  end
end

Так что да, это другое - я не уверен, что это лучше, это просто то, что я придумал. Мой mutation_type.rb намного толще, что мне не нравится.

Вы не четко сформулировали какие-либо цели или проблемы, чтобы помочь вам получить более конкретный ответ.

Есть еще один метод, который я использовал недавно. Мы также не используем React, и было странно использовать GraphQL::Relay::Mutation.define для описания мутаций.

Вместо этого мы опишем fields, (например: app/graphql/mutations/create_owner.rb)

Mutations::CreateOwner = GraphQL::Field.define do
  name 'CreateOwner'
  type Types::OwnerType
  description 'Update owner attributes'

  argument :name, !types.String
  argument :description, types.String

  resolve ->(_obj, args, _ctx) do
    Owner.create!(args.to_h)
  end
end

Тогда в вашем app/graphql/types/mutation_type.rb вы добавляете:

field :createOwner, Mutations::CreateOwner

Это может быть изменено в дальнейшем путем извлечения распознавателей в их собственные классы распознавателей.

Без определенных передовых методов, которые мне удалось обнаружить, это был довольно чистый способ решения этой проблемы.

Другие вопросы по тегам