Graphql-ruby: Mutations not being loaded

Created on 30 Jun 2019  路  15Comments  路  Source: rmosolgo/graphql-ruby

Hello community,

I'm reaching to this section as I have been working on several weeks to understand whether this is potentially a bug.

The piece of code below regards to a login mutation. It takes email and password, then ruby-graphql should return a token. The actual values for email and password are passed as variables.

mutation {
  token: login(
    email: "...",
    password: "..."
  )
}

In production environment GraphQL spills an odd error regarding mutations not being configured.

{
  "errors": [
    {
      "message": "Schema is not configured for mutations",
      "locations": [
        {
          "line": 1,
          "column": 1
        }
      ],
      "path": [
        "mutation"
      ],
      "extensions": {
        "code": "missingMutationConfiguration"
      }
    }
  ],
  "extensions": {}
}

Any ideas?

All 15 comments

Hey @cassiopagnoncelli I like to help but need more information about your schema setup. Specifically the call site where you have

class MySchema < GraphQL::Schema
  # Required:
  query Types::Query
  # Optional:
  mutation Types::Mutation
  subscription Types::Subscription
end

And your equivalent of Types::MutationType class.

From the error, it looks like it might be broken right at the Schema def level.

@daemonsy Thank you so much, here it is the schema definition

require 'apollo/tracing'

class ApiSchema < GraphQL::Schema
  max_depth 5
  max_complexity 400

  use GraphQL::Batch
  use ApolloTracing.new
  # use BatchLoader::GraphQL
  # lazy_resolve BatchLoader, :sync

  query(Types::QueryType)
  mutation(Types::MutationType)
end

ApiSchema.middleware <<
  GraphQL::Schema::TimeoutMiddleware.new(max_seconds: 5) do |err, query|
    Rails.logger.info("GraphQL Timeout: #{query.query_string}")
  end

For mutations, we have mutation_type.rb:

module Types
  class MutationType < Types::BaseObject

    field :login, mutation: Mutations::Login
    field :recoverPassword, mutation: Mutations::UserRecoverPassword

    # (...)
  end
end

Maybe it might be useful adding base_mutation.rb itself as that might be part of the problem:

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

  # Add your custom classes if you have them:
  # This is used for generating payload types
  object_class Types::BaseObject

  # This is used for return fields on the mutation's payload
  field_class Types::BaseField

  # This is used for generating the `input: { ... }` object type
  input_object_class Types::BaseInputObject

end

I have no clue where the issue is. Any idea?

Hey @cassiopagnoncelli the mutation looks very standard to me.

I've bumped into cases where there was syntax error (or missing some required setup field) and it didn't throw a direct error (rather something XYZ constant is not loaded), not sure if it's something like that in your case.

I'm going try to reduce this to see if that's where the problem is. If you're actively on this, I suggest that maybe trying to comment out more optional things (such as apollo tracing, the middleware etc) to see one of those lines is part of the cause.

I think you probably cannot share your working code in Mutations::Login and Mutations::UserRecoverPassword.

Maybe instead I'll try to create a basic working setup of mutations on a demo (probably here) so you can change Ruby / GraphQL versions to see if that's the cause of your problem.

Hello @daemonsy

True, it actually works fine on dev environment so should be a typo. I tried removing everything from plugins to modules in a way to have Ruby-GraphQL as simple as possible, result is problem persists.

I have probably reviewed all configuration files (actually it's mostly a standard Rails 5.2.2 app) and can't find the issue. I'm giving my best to find where the issue is, but I can't find a hint where the problem might be. I'm probably working on this issue for a month :/

I'm trying to think what _could_ be different in development vs. production. One thing that stood out is parallelism -- are you using a multi-threaded or multiprocess server like Puma or Phusion Passenger? I wonder if a process could somehow fork _before_ the schema is _totally_ booted, and then the forked schema isn't all set up properly.

I don't really have a clear suggestion, except something that _sometimes_ helps with these loading issues. Try adding at the _very bottom_ of api_schema.rb:

# Ensure that the schema is booted eagerly, instead of before the first query 
ApiSchema.graphql_definition 

It might work 馃槄 . (Longer term, I'm trying to simplify schema boot over at #2363.)

Hi @rmosolgo

Great to see you in this discussion. Yes it's running behind Puma though it looks quite standard setup.

I tried that, it doesn't work, tried in other places too (like application.rb), error persists. To give more glimpse on this error, QueryType always loads alongside libs (batch and apollo), however MutationType is never loaded on production.

Overview is,

  • dev environment runs smoothly without errors
  • simpler setup didn't solve (removing libs)
  • no apparent errors on logs
  • differences between dev and prod environment are mostly eliminated with Docker (is there a recommended "special" version of Rails and Ruby to try it?)
  • puma + nginx + docker stack is roughly the same for dev and prod environments (apart from domain binding, https redirection, etc)

I'm wondering if it takes something special to have mutations working on prod?

馃槚 Sorry it didn't help!

something special to have mutations working on prod?

No, not that I know of! GraphQL-Ruby is about 4 years old and I'd imagine it has thousands of running instances, but I haven't heard of this issue until now 馃槚

Question, what does it says if you run the following ?

mutation {
  login(email: "...",password: "...") {
    token
  }
}

It's actually the first time I've seen your syntax XD (as for why that would work on dev on not on prod is anyone's guess)

Hello @nekogami

It returns

{
  "errors": [
    {
      "message": "Selections can't be made on scalars (field 'login' returns String but has selections [token])",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "mutation",
        "login"
      ],
      "extensions": {
        "code": "selectionMismatch",
        "nodeName": "field 'login'",
        "typeName": "String"
      }
    }
  ],
  "extensions": {}
}

Any idea on what the issue is?

Thank you so much!

From what I understand, in your returned object, token is not a string but an array, if so, you will have to change your selection value.

IE:
if object.token is an array of string, the token field inside the return type has to be declared as [String]

@nekogami No not really, turns out that the query and mutation are well-formed, it actually returns a value, look:

{
  "data": {
    "token": "eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7ImlkIjoxNjQ1MywibWVyY2hhbnRJZCI6MTE4NSwiZW1haWwiOiJub2VseXBpY29sbG9AZ21haWwuY29tIiwicGVybWlzc2lvbnMiOm51bGwsIm5hbWUiOiJOb2VseSBQaWNvbGxvIn0sImV4cCI6MTU2NzEzMTY3N30.DosoZV5f6_uRdERR9p5paRVjYBu5Fz3H137uslUGel8"
  },
  "extensions": {}
}

I just run it in my machine under Docker on development environment. When I deploy to production, mutations won't work. Types::QueryType is recognized and queries work perfectly, but not for Types::MutationType as they aren't even loaded.

hey @cassiopagnoncelli did you ever get to the root of the issue?

@daemonsy Not really, what I did was to actually recode from scratch and now it's up & running.

@cassiopagnoncelli sorry to hear that you have to redo the schema from scratch. Well at least the problem's gone :)

I'm going to close the issue, if you bump into some issue like this 馃 in the future and discover a gotcha, be glad to take a PR to document it.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

KevinColemanInc picture KevinColemanInc  路  3Comments

amozoss picture amozoss  路  3Comments

gastonmorixe picture gastonmorixe  路  3Comments

theodorton picture theodorton  路  3Comments

rmosolgo picture rmosolgo  路  4Comments