Apollo-link-rest: What should I do when the server returns non-graphql compliant result

Created on 20 Jun 2018  ·  6Comments  ·  Source: apollographql/apollo-link-rest

what I am trying to do is to query account information to bcoin via its http rest interface.
To do so, I must

  1. ask names of all existing accountName by calling GET /wallet/:id/account
  2. ask for account detail by GET /wallet/:id/account/:accountName

problem is that the first call will return something like ["default", "mySecondAccountName"]
which I don't know how to parse as graphql response, nor pass directly to second GET

e.g. when I tried to query by following query,

query (id: "primary") @rest(type: AccountName, path: "/wallet/:id/account") {
  default

I will get Error: Network error: Cannot create property 'default' on string 'default'

I couldn't find any clue in document, but this seems very common case so I must be missing something very simple. I really appreciate if someone could point me out what I should look for

question❔

Most helpful comment

@joemphilips I think you should use a typePatcher

I use it to handle non graphql compliant response like

{
   "100": {
      "id": 100,
      "node_id": 105,
      "category_id": 8,
      "title": "Title 100",
      "highlight": true
   },
   "138": {
      "id": 138,
      "node_id": 106,
      "category_id": 7,
      "title": "Title 138",
      "highlight": false
   },
   "140": {
      "id": 140,
      "node_id": 101,
      "category_id": 9,
      "title": "Title 140",
      "highlight": false
   },
   "158": {
      "id": 158,
      "node_id": 146,
      "category_id": 4,
      "title": "Title 158",
      "highlight": false
   }
}

Query definition

import { gql } from 'apollo-boost';

export const GET_NEWS_QUERY = gql`
  query getNews {
    News @rest(type: "News", path: "news") {
      data
    }
  }
`;

RestLink configuration

const restLink = new RestLink({
  uri: API_URL,
  typePatcher: {
    News: (data, outerType) => {
      if (outerType === 'News') {
        data = Object.keys(data).map(id => {
          const result = data[id];

          if (result) {
            return {
              __typename: 'News',
              ...result
            };
          }
        });
      }

      return { data };
    }
  }
});

Query usage
```js
render() {
return (
{({ loading, error, data }) => {
if (loading) {
return (

Loading...

);
}

      if (error) {
        return (
          <View>
            <Text>Error :(</Text>
          </View>
        );
      }

      const news = data && data.News && data.News.data;
      const filteredNews = news && news.filter(Boolean);

      return (
        <Styles.Container>
          <Carousel
            data={filteredNews}
            handleOnPress={this.navigateToScreen}
          />
        </Styles.Container>
      );
    }}
  </Query>
);

}
`
``

All 6 comments

I'm only guessing as I'm not familiar with bcoin, but here is a suggestion:

query Account(id: $id){
   account(id: $id) @rest(type: "[String]", path: "/wallet/:id/account")
}

Then you get the results of that out of data and pass it to a new query that gets the account details.

Thanks for kind and fast response. @fbartho
Maybe I should have not mentioned to bcoin, my problem is more simple

In the example of @export directive in the document, it has example of calling REST endpoint twice.
My question is, what should I do when the first query in this example returns an array of Scalar instead of array of object?
since it has no key, it seems there are no way to specify which argument should be exported.

I also tried not using @export and instead query as you mentioned, but the result of fetch is {}
with the following warning

Missing field account in {}

by the way, I think in your suggestion

query Account(id: $id)

should be

query Account($id: id)

I found out that when I run the command you have suggested, i.e

query Account(id: $id){
   account(id: $id) @rest(type: "[String]", path: "/wallet/:id/account")
}

It wont actually execute any query and it will just returns {} as data .
so I must specify { theFieldNameIDesire } after the line of account, problem is that I have no field name to specify :(

@joemphilips I think you should use a typePatcher

I use it to handle non graphql compliant response like

{
   "100": {
      "id": 100,
      "node_id": 105,
      "category_id": 8,
      "title": "Title 100",
      "highlight": true
   },
   "138": {
      "id": 138,
      "node_id": 106,
      "category_id": 7,
      "title": "Title 138",
      "highlight": false
   },
   "140": {
      "id": 140,
      "node_id": 101,
      "category_id": 9,
      "title": "Title 140",
      "highlight": false
   },
   "158": {
      "id": 158,
      "node_id": 146,
      "category_id": 4,
      "title": "Title 158",
      "highlight": false
   }
}

Query definition

import { gql } from 'apollo-boost';

export const GET_NEWS_QUERY = gql`
  query getNews {
    News @rest(type: "News", path: "news") {
      data
    }
  }
`;

RestLink configuration

const restLink = new RestLink({
  uri: API_URL,
  typePatcher: {
    News: (data, outerType) => {
      if (outerType === 'News') {
        data = Object.keys(data).map(id => {
          const result = data[id];

          if (result) {
            return {
              __typename: 'News',
              ...result
            };
          }
        });
      }

      return { data };
    }
  }
});

Query usage
```js
render() {
return (
{({ loading, error, data }) => {
if (loading) {
return (

Loading...

);
}

      if (error) {
        return (
          <View>
            <Text>Error :(</Text>
          </View>
        );
      }

      const news = data && data.News && data.News.data;
      const filteredNews = news && news.filter(Boolean);

      return (
        <Styles.Container>
          <Carousel
            data={filteredNews}
            handleOnPress={this.navigateToScreen}
          />
        </Styles.Container>
      );
    }}
  </Query>
);

}
`
``

Sorry to respond late. your solution seems to not work for string/scalar of array. But it seems to be fixed . I will try again. And may reopen if I'm keep having trouble. Thanks.

Was this page helpful?
0 / 5 - 0 ratings