Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sub fields returning null #31

Open
fazulk opened this issue Feb 20, 2021 · 8 comments
Open

Sub fields returning null #31

fazulk opened this issue Feb 20, 2021 · 8 comments
Labels
needs investigation The root cause is unclear and needs to be uncovered

Comments

@fazulk
Copy link

fazulk commented Feb 20, 2021

Having an issue returning sub fields.. Not sure If there is something I need to add to resolvers, but have attempted that as well with no luck. Name returns fine, but null is coming back for any fields inside location. Even though the data exists in the same format. Am i missing something?

type Query {
    findPeople(
        personId: [String!]
    ): [Person]
}

type Person {
    location: Location
    name: String
}

type Location {
    city: String
}
@jneurock
Copy link
Collaborator

It's hard to say if you're missing something without knowing a bit more about your entire setup. I'm curious how you're relating the records in Mirage, if you're having trouble even after adding your own resolvers. Feel free to chat in the Mirage Discord, too.

@ronbravo
Copy link

ronbravo commented Nov 1, 2021

Leaving this comment in case anyone else runs into this issue. I found somewhat of a workaround based on the recommendation from this ticket. I basically had to do the changes shown below. Please note I changed some of the code due to the nature of the private project I am on so some of the things are too exact, but should give a general idea. Essentially, make sure you have resolvers for fields that are coming back as null.

The Schema:

type Response {
  name: String,
  payload: ResponsePayload
}

type ResponsePayload {
  id: String,
  name: String,
  data: ResponsePayloadData
}

type ResponsePayloadData {
  name: String,
  nickname: String,
}

The Query:

const UPDATE_NICKNAME = gql`
  mutation UpdateUserNickname($userid: String!, $body: String!) {
    UpdateNickname(userid: $userid, body: $body) {
      payload {
        data {
          nickname
        }
      }
    }
  }
`;

The Resolver in the Mock Server:

createServer({
  routes() {
    const graphQLHandler = createGraphQLHandler(GRAPH_QL_SCHEMA, this.schema, {
      resolvers: {
        Mutation: {
          UpdateNickname: (obj, args, context, info) => {
            const result = {
              payload: {
                data: {
                  nickname: 'My Nickname',
                },
              },
            };

            return result;
          }
        },
        ...

        // NOTE: Here are the resolvers for the fields of specific types where the values kept coming back as null.
        ResponsePayload: {
          data: ({ data }) => data,
        },
        Response: {
          payload: ({ payload }) => payload,
        }
      },
    });
    this.post('/graphql', graphQLHandler);
  },
  ...
});

I'm not sure why this happens (maybe something to do with nested response values?) but my hope is that this helps someone who may run into a similar issue. Even with this little gotcha, overall this library is very useful. Thanks to the team for putting it together.

@jneurock
Copy link
Collaborator

jneurock commented Nov 3, 2021

Leaving this comment in case anyone else runs into this issue. I found somewhat of a workaround based on the recommendation from this ticket. I basically had to do the changes shown below. Please note I changed some of the code due to the nature of the private project I am on so some of the things are too exact, but should give a general idea. Essentially, make sure you have resolvers for fields that are coming back as null.

The Schema:

type Response {
  name: String,
  payload: ResponsePayload
}

type ResponsePayload {
  id: String,
  name: String,
  data: ResponsePayloadData
}

type ResponsePayloadData {
  name: String,
  nickname: String,
}

The Query:

const UPDATE_NICKNAME = gql`
  mutation UpdateUserNickname($userid: String!, $body: String!) {
    UpdateNickname(userid: $userid, body: $body) {
      payload {
        data {
          nickname
        }
      }
    }
  }
`;

The Resolver in the Mock Server:

createServer({
  routes() {
    const graphQLHandler = createGraphQLHandler(GRAPH_QL_SCHEMA, this.schema, {
      resolvers: {
        Mutation: {
          UpdateNickname: (obj, args, context, info) => {
            const result = {
              payload: {
                data: {
                  nickname: 'My Nickname',
                },
              },
            };

            return result;
          }
        },
        ...

        // NOTE: Here are the resolvers for the fields of specific types where the values kept coming back as null.
        ResponsePayload: {
          data: ({ data }) => data,
        },
        Response: {
          payload: ({ payload }) => payload,
        }
      },
    });
    this.post('/graphql', graphQLHandler);
  },
  ...
});

I'm not sure why this happens (maybe something to do with nested response values?) but my hope is that this helps someone who may run into a similar issue. Even with this little gotcha, overall this library is very useful. Thanks to the team for putting it together.

Thanks for sharing. I'm not sure why you need to add resolvers for the ResponsePayload and Response types 🤔 The library should be doing this by default. It's definitely worth investigating. If you don't mind, could you open a separate issue for this so it's easier to work on?

@ronbravo
Copy link

ronbravo commented Nov 9, 2021

@jneurock Yes, in a few days I can raise an issue for this and put together a sample repo for review. I will try to match the configuration in my current project just in case my setup of the library is incorrect in some way.

@jneurock
Copy link
Collaborator

jneurock commented Nov 9, 2021

Thanks, @ronbravo!

@dbollinger
Copy link

I'm experiencing this as well, currently trying with a relatively simple schema like the OP's example:

type Location {
  city: String
  state: String
}
 
type Event {
  id: String
  description: String
  location: Location
}

And I can confirm using the workaround to explicitly grab this field in a resolver when creating the mirage-server achieves the desired effect:

resolvers: {
  Event: {
     location: ({ location }) => location
   }
 }

@jneurock
Copy link
Collaborator

I'm experiencing this as well, currently trying with a relatively simple schema like the OP's example:

type Location {
  city: String
  state: String
}
 
type Event {
  id: String
  description: String
  location: Location
}

And I can confirm using the workaround to explicitly grab this field in a resolver when creating the mirage-server achieves the desired effect:

resolvers: {
  Event: {
     location: ({ location }) => location
   }
 }

Can you share the query where you see the issue? What's hard for me to understand is why this is happening. I have a test that covers nested records. Thanks!

@jneurock jneurock added the needs investigation The root cause is unclear and needs to be uncovered label Jan 16, 2022
@jneurock
Copy link
Collaborator

jneurock commented Jan 27, 2022

Update: Through a Discord chat I was able to tweak a test mutation in the library and reproduce the issue. At least, the issue where related records result in null field values.

I'd have to see the actual resolver code in each case above to compare but in my case the issue came from returning records that were not Mirage model instances.

For example, there's a custom resolver test involving a mutation. The resolver code looks like this:

resolvers: {
  Mutation: {
    optionallyMutateTestObject(_obj, { id, input }, context) {
      return context.mirageSchema.db.testObjects.update(id, input);
    },
  },
}

This works fine if I don't want to return related records but that may just be by chance. This doesn't return a Mirage model instance. If I seed my database with a record related to this and I ask for the related fields in my GraphQL mutation, it will fail.

In order for me to successfully resolve this with related records, I need to change my resolver like this:

resolvers: {
  Mutation: {
    optionallyMutateTestObject(_obj, { id, input }, context) {
      return context.mirageSchema.testObjects.find(id).update(input);
    },
  },
}

There's a subtle difference in the Mirage API used but the latter will return a Mirage model and Mirage GraphQL knows how to auto-resolve its fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs investigation The root cause is unclear and needs to be uncovered
Projects
None yet
Development

No branches or pull requests

4 participants