4

The rest api that I have to use provides data over multiple endpoints. The objects in the results might have relations that are are not resolved directly by the api, it rather provides ids that point to the actual resource.

Example: For simplicity's sake let's say a Person can own multiple Books.

Now the api/person/{i} endpoint returns this:

{ id: 1, name: "Phil", books: [1, 5, 17, 31] }

The api/book/{i} endpoint returns this (note that author might be a relation again):

{ id: 5, title: "SPRINT", author: 123 }

Is there any way I can teach the apollo client to resolve those endpoints in a way that I can write the following (or a similar) query:

query fetchBooksOfUser($id: ID) {
  person (id: $id) {
    name,
    books {
      title
    }
  }
}
Philip Feldmann
  • 7,887
  • 6
  • 41
  • 65

2 Answers2

5

I didn't try it (yet) in one query but sould be possible.

Read docs strating from this

At the beggining I would try with sth like:

query fetchBooksOfUser($id: ID) {
  person (id: $id) @rest(type: "Person", path: "api/person/{args.id}") {
    name,
    books @rest(type: "Book", path: "api/book/{data.person.books.id}") {
      id,
      title
    }
  }
}

... but it probably won't work - probably it's not smart enough to work with arrays.


UPDATE: See note for similiar example but using one, common parent-resolved param. In your case we have partially resolved books as arrays of objects with id. I don't know how to use these ids to resolve missing fields () on the same 'tree' level.


Other possibility - make related subrequests/subqueries (someway) in Person type patcher. Should be possible.

Is this really needed to be one query? You can provide ids to child containers, each of them runing own query when needed.


UPDATE: Apollo will take care on batching (Not for REST, not for all graphql servers - read docs).

'it's handy' to construct one query but apollo will cache it normalizing response by types - data will be stored separately. Using one query keeps you within overfetching camp or template thinking (collect all possible data before one step rendering).

Ract thinking keeps your data and view decomposed, used when needed, more specialised etc.

<Person/> container will query for data needed to render itself and list of child-needed ids. Each <Book/> will query for own data using passed id.

xadm
  • 8,219
  • 3
  • 14
  • 25
  • Thanks for the answer. It doesn’t necessarily need to be one query but it would be handy. Can you provide an example or documentation to the batching you just mentioned? I’m very unsure on where to go from here. – Philip Feldmann May 07 '19 at 19:42
  • In order for cascaded queries to work, you might want to use the `@export` directive, and the `exportVariables`, as suggested here https://www.apollographql.com/docs/link/links/rest/#example-1 – edu_ May 26 '20 at 01:42
1

As an alternative, you could set up your own GraphQL back-end as an intermediary between your front-end and the REST API you're planning to use.

It's fairly easy to implement REST APIs as data sources in GraphQL using Apollo Server and a package such as apollo-datasource-rest which is maintained by the authors behind Apollo Server.

It would also allow you to scale if you ever have to use other data sources (DBs, 3rd party APIs, etc.) and would give you full control about exactly what data your queries return.

Thomas Hennes
  • 9,023
  • 3
  • 27
  • 36