3

I am connecting GraphQL with REST endpoints, I confirmed that whenever I am calling http://localhost:3001/graphql it is hitting REST endpoint and it is returning JSON response to GraphQL server, but I am getting an empty response from GraphQL server to GUI as follows:

{
  "data": {
    "merchant": {
      "id": null
    }
  }
}

Query (decoded manually):

http://localhost:3001/graphql?query={
  merchant(id: 1) {
    id
  }
}

Below is how my GraphQLObjectType looks like:

const MerchantType = new GraphQLObjectType({
  name: 'Merchant',
  description: 'Merchant details',
  fields : () => ({
    id : {
      type: GraphQLString // ,
      // resolve: merchant => merchant.id
    },
    email: {type: GraphQLString}, // same name as field in REST response, so resolver is not requested
    mobile: {type: GraphQLString}
  })
});


const QueryType = new GraphQLObjectType({
  name: 'Query',
  description: 'The root of all... queries',
  fields: () => ({
    merchant: {
      type: merchant.MerchantType,
      args: {
        id: {type: new GraphQLNonNull(GraphQLID)},
      },
      resolve: (root, args) => rest.fetchResponseByURL(`merchant/${args.id}/`)
    },
  }),
});

Response from REST endpoint (I also tried with single object in JSON instead of JSON array):

[
  {
    "merchant": {
      "id": "1",
      "email": "a@b.com",
      "mobile": "1234567890"
    }
  }
]

REST call using node-fetch

function fetchResponseByURL(relativeURL) {

  return fetch(`${config.BASE_URL}${relativeURL}`, {
    method: 'GET',
    headers: {
      Accept: 'application/json',
    }
  })
  .then(response => {
    if (response.ok) {
      return response.json();
    }
  })
  .catch(error => { console.log('request failed', error); });

}

const rest = {
  fetchResponseByURL
}

export default rest

GitHub: https://github.com/vishrantgupta/graphql
JSON endpoint (dummy): https://api.myjson.com/bins/8lwqk

Edit: Adding node.js tag, may be issue with promise object.

Vishrant
  • 15,456
  • 11
  • 71
  • 120
  • 1
    There's probably a mismatch between the shape of the response from the REST endpoint and your schema. Can you update your question to include the full response from the REST endpoint? – Daniel Rearden Aug 19 '18 at 05:00
  • thanks @DanielRearden for checking this out. I have updated my question with endpoint response. – Vishrant Aug 19 '18 at 05:04
  • what is `rest` in `resolve: (root, args) => rest.fetchResponseByURL(`merchant/${args.id}/`)` ? – xadm Aug 19 '18 at 07:14
  • that is an export from other js file `export default rest` this have a REST `fetch` `fetchResponseByURL` method – Vishrant Aug 19 '18 at 07:17
  • @xadm I have updated my question with that details – Vishrant Aug 19 '18 at 07:19
  • return promise? – xadm Aug 19 '18 at 07:29
  • https://kevincoletta.com/2016/01/21/graphql-resolve-returns-null-values/ - maybe it's related – xadm Aug 19 '18 at 07:38
  • Your REST endpoint seems to respond with an array but your field expects an object. The array then obviously has no property `id`. To fix this maybe return the first element or use `.then(ms => ms.find(m => m.id === args.id))`. Furthermore I would suggest to remove the `catch` handler in the fetch function since it will turn the promise into a resolved promise with value `undefined`. It is better to let it go through to the GraphQL resolve (at least in development). – Herku Aug 19 '18 at 10:33
  • @Herku I have tried by returning just a single json object instead of array but the issue is still same. I have created a github repo https://github.com/vishrantgupta/graphql and using a dummy `JSON` service https://api.myjson.com/bins/8lwqk – Vishrant Aug 19 '18 at 14:25
  • @xadm I tried the solution given in that link, but no luck. – Vishrant Aug 19 '18 at 14:33

2 Answers2

2

Your fetchResponseByURL function get empty string.

I think the main problem is that you are using wrong function to get the your JSON string, please try to install request-promise and use it to get your JSON string.

https://github.com/request/request-promise#readme

something like

var rp = require('request-promise');
function fetchResponseByURL(relativeURL) {
  return rp('https://api.myjson.com/bins/8lwqk')
    .then((html) => {
      const data = JSON.parse(html)
      return data.merchant
    })
    .catch((err) => console.error(err));
  // .catch(error => { console.log('request failed', error); });

}
Yu Huang
  • 3,085
  • 2
  • 24
  • 22
  • I implemented `request-promise` but still the same result. I cross verified if I am getting an empty JSON response from REST endpoint but that is not the case. I have shared the execution of this flow https://drive.google.com/open?id=1aZkw66S7JUO4wYxnDL-rUiWwm5Dnho8l – Vishrant Aug 19 '18 at 19:12
  • I don't know what's your requirements. Do you store all your data in JSON with the link 'https://api.myjson.com/bins/8lwqk'? And you want to get the specific merchant info by id? – Yu Huang Aug 19 '18 at 19:54
  • It will be a link from like how I posted above and response `Content-Type application/json` – Vishrant Aug 19 '18 at 20:03
  • I have updated code, try to use the fetchResponseByURL function in my answer – Yu Huang Aug 19 '18 at 20:11
  • graphql's resolver, it will auto match the object field. So you should return the merchant object at the end of resolver. Then it can filter the fields which you want. – Yu Huang Aug 19 '18 at 20:14
1

In this case using data.merchant solved my problem. But the above suggested solution i.e., use of JSON.parse(...) might not be the best practice because if there are no object in JSON, then expected response might be as follows:

{
  "data": {
    "merchant": null
  }
}

Instead of fields to be null.

{
  "data": {
    "merchant": {
      "id": null // even though merchant is null in JSON, 
                 // I am getting a merchant object in response from GraphQL
    }
  }
}

I have updated my GitHub: https://github.com/vishrantgupta/graphql with working code.

Vishrant
  • 15,456
  • 11
  • 71
  • 120