Unable to resolve search query with iterables


#1

With sambhav-gore’s help I was able to get my github GraphQL proxy server working. here is my query string:

{
  search(first: 10, type: REPOSITORY, query: "created:<2008-06-30 sort:updated") {
    nodes {
      ... on Repository {
        name
        owner {
          login
          avatarUrl
          ... on User {
            followers(first: 5) {
              nodes {
                name
              }
            }
          }
        }
      }
    }
  }
}

When I run this query in the explorer it seems to run correctly, and returns all of the data I need. YEAH GRAPHQL! However, when I attempt to get and resolve the data from my own GraphQL server (Apollo Server) it is unable to resolve the followers content. I get an error that reads:

“Error: Expected Iterable, but did not find one for field Owner.followers.”

I believe this is because if you look at what is passed followers seems to be a json object instead of a list. It looks like this:

{
"followers": {
              "nodes": [
                {"name": "Ferdinand Svehla"},
                {"name": ""},
                {"name": "Philipp Markovics"},
                {"name": "Samo Korosec"},
                { "name": "Michael Aufreiter" }
              ]}
}

I’m using node-fetch to do the call, here is my resolver function:

return fetch('https://api.github.com/graphql', {
      method: 'post',
      headers: {
        Authorization: `bearer ${
          process.env.GITHUB_TOKEN
        }`,
      },
      body: JSON.stringify({query, variables})
    })
    .then(response => response.json())
    .then(data => {
      return data.data.search.nodes
    })
    .catch((e) => {
      console.log(e)
    })
  }
  1. Can someone explain if I’m doing something wrong? Is there a resolver step I’m missing? I’m guessing I can do some fancy MAP function on the returned results to munge the results into the JSON shape I want, but that seems against the whole idea of GraphQL.

2 Is it normal to have to return data.data.search.nodes from a query? Seems strange and unintuitive to have those extra JSON levels included in the data response.

  1. Is there a way to force Github to return a blank list for followers? With my query some owners have no followers, and so it’s skipped in the return data. This will cause me problems too I’m guessing.

#2

Are you creating your own graphQL server for your client?
Or is your client application directly connecting to github’s api ?

Edit: As you said you are making your own graphQL server, I think you need to process this result and then return the shape that you desire in your resolver. (That is what I am doing in my application as well).

FYI, I do not get any errors when I run the following (on server side):

const fetch = require("node-fetch");
const access_token = "XXXX";

const query = `{
    search(first: 10, type: REPOSITORY, query: "created:<2008-06-30 sort:updated") {
      nodes {
        ... on Repository {
          name
          owner {
            login
            avatarUrl
            ... on User {
              followers(first: 5) {
                nodes {
                  name
                }
              }
            }
          }
        }
      }
    }
  }`;

return fetch("https://api.github.com/graphql", {
  method: "post",
  headers: {
    Authorization: `bearer ${access_token}`
  },
  body: JSON.stringify({ query })
})
  .then(response => {
    return response.json();
  })
  .then(responseJson => {
    console.log(responseJson.data.search.nodes);
    return responseJson;
  })
  .catch(e => {
    console.log("Something went wrong");
  });

#3

Edit 2:

Here is some pseudo code from my application’s resolver function :

// issues-connectors.js
const Issue = {
    async getAll() {
        // fetch from api
        const response = await fetch(OPTIONS);
        const responseJson = await response.json();

       // process the response:
        const openIssues = responseJson
          .map((issue) => MAP_ISSUES_LOGIC)
          .filter(issue => FILTER_LOGIC)

        // resolve it:
        return Promise.resolve(openIssues);
    }
}

And the resolvers look as:

const resolvers = {
  Query: {
    issues: () => Issue.getAll()
  }
};

#4

thanks again sambhav-gore. Yes I just went ahead and created my on conversion method.

-=Steve