Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graphql Field doesn't exist on type

After skimming through the docs of Graphql I've started to implement it on a toy rails/reactJS project. The projects allows an user to sign in through devise then access a dummy /artist route that displays a list of artists. Everything seems to work fine until I try to consume api data with GraphQL from the react app to get artists and display them.

On the server side, I have a graphql_controller.rb such as:

class GraphqlController < ApiController
  rescue_from Errors::Unauthorized do |exception|
    render json: {errors: ['Unauthorized.']}, status: :unauthorized
  end

  def index
    result = Schema.execute params[:query], variables: params[:variables], context: context
    render json: result, status: result['errors'] ? 422 : 200
  end

private

  def context
    token, options = ActionController::HttpAuthentication::Token.token_and_options request
    {
      ip_address: request.remote_ip
    }
  end
end

Then, following to my model logic, I have set up graphql under graph/ with the following files:

graph/queries/artist_query.rb

ArtistQuery = GraphQL::ObjectType.define do
  name 'ArtistQuery'
  description 'The query root for this schema'

  field :artists, types[Types::ArtistType] do
    resolve(->(_, _, _) {
      Artist.all
    })
  end
end

types/artist_type.rb

Types::ArtistType = GraphQL::ObjectType.define do
  name 'Artist'
  description 'A single artist.'

  field :id, !types.ID
  field :name, types.String
  field :description, types.String
end

schema.rb

Schema = GraphQL::Schema.define do
  query ArtistQuery
end

On the client side, for the sake of keeping things organized, I use 3 files to render this artist list:

First, ArtistSchema.js

import { gql } from 'react-apollo';

const artistListQuery = gql`
    {
        query {
            artists {
                id
                name
                description     
            }
        }
    }
`;

export default artistListQuery;

Then, an Artist.js

import React, { Component } from 'react';

class Artist extends Component {
    render() {
        return (
            <tr>
                <td>{this.props.index + 1}</td>
                <td>{this.props.data.name}</td>
                <td>{this.props.data.description} min</td>
            </tr>
        );
    }
}

export default Artist;

And finally, wrapping these two together in a larger layout: Artists.jsx:

import React, { Component } from 'react';
import {graphql} from 'react-apollo';
import Artist from './Artist';
import artistListQuery from './ArtistSchema';

class Artists extends Component {
    render() {
        if(this.props.data.loading) {
            return (<p>Loading</p>)
        } else {

            console.log(this.props.data)
            const ArtistsItems = this.props.data.artists.map((data,i) => {
                return (<Artist key={i} index={i} data={data}></Artist>);
            });
            return (
                <div>
                    <h1>Artists</h1>
                    <table className="table table-striped table">
                        <thead>
                        <tr>
                            <th>#</th>
                            <th>Name</th>
                            <th>Description</th>
                        </tr>
                        </thead>
                        <tbody>
                        { ArtistsItems }
                        </tbody>
                    </table>
                </div>
            );
        }

    }
}

export default graphql(artistListQuery)(Artists);

What happens when this code is executed:

On server-side (sorry for the unformatted output, but it displays like this in console):

Processing by GraphqlController#index as */*
18:49:46 api.1  |   Parameters: {"query"=>"{\n  query {\n    artists {\n      id\n      name\n      description\n      __typename\n    }\n    __typename\n  }\n}\n", "operationName"=>nil, "graphql"=>{"query"=>"{\n  query {\n    artists {\n      id\n      name\n      description\n      __typename\n    }\n    __typename\n  }\n}\n", "operationName"=>nil}}

Followed by the error:

Completed 422 Unprocessable Entity in 36ms (Views: 0.2ms | ActiveRecord: 0.0ms)

On the client side, if I monitor Network > Response for graphql, I (of course) receive a 422 error code and the following error message:

{"errors":[{"message":"Field 'query' doesn't exist on type 'ArtistQuery'","locations":[{"line":2,"column":3}],"fields":["query","query"]}]}

I assume my query is not done correctly. I have been trying various queries formats (from docs or gists examples) but I cannot end finding a correct way to get back my artist data.

What am I doing wrong?

like image 272
gastngouron Avatar asked Oct 01 '18 16:10

gastngouron


4 Answers

I don't think this is the issue for this particular case, but I was getting this error and it turned out to be due to a simple syntax error. Query attributes need to be in camelCase format, not under_score format. Maybe this will help someone else that lands here when searching for this error like I did.

like image 142
Jeremy_inPDX Avatar answered Nov 12 '22 13:11

Jeremy_inPDX


You might need to use a newer API endpoint URL version.

Example Request URL: https://shopify-graphiql-app.shopifycloud.com/api/*2022-01*/graphql

like image 24
Matthew Soyka Avatar answered Sep 22 '22 14:09

Matthew Soyka


In my case the issue was that I had a structure like this:

module Types
  class SomeType < Types::BaseObject
    field :comparator,
          Types::ComparatorType
    field :options,
          [Types::OptionType]
  end
end

BUT in the query I had other nested structure called data that I forgot about:

mutation {
  myMutation(
    ...  
  ) {
    someType {
      comparator {
        ...
      }
      data {
        options {
           ...
        }
      }
    }
  }
}

So after changing SomeType class to add that missing key solved my issue. So now it look like this:

module Types
  class SomeType < Types::BaseObject
    field :comparator,
          Types::ComparatorType
    field :data,
          Types::DataType
  end
end

# New file
module Types
  class DataType < Types::BaseObject
    field :options,
          [Types::OptionType]
  end
end
like image 2
dani24 Avatar answered Nov 12 '22 13:11

dani24


The GQL query you sent is malformed, it is asking for the query field of Query root object. Use this instead:

const artistListQuery = gql`
    query UseTheNameYouWantHere {
        artists {
            id
            name
            description     
        }
    }
`;

BTW, you can add graphiql gem (https://github.com/rmosolgo/graphiql-rails) to have a playground with your GraphQL API.

like image 1
MrYoshiji Avatar answered Nov 12 '22 13:11

MrYoshiji