apollo-feature-requests icon indicating copy to clipboard operation
apollo-feature-requests copied to clipboard

[apollo-datasource-rest] Handling 404 errors

Open timReynolds opened this issue 5 years ago • 2 comments

From my understanding of GraphQL data that is not available as part of a request should be returned as null, therefore allowing other parts of the query to return for the client to render as best.

If this is the case and your rest API returns 404 status codes however you'll need to write something like the following to capture the errors and return null;

      try {
        return await dataSources.listingApi.getListing(args.reference);
      } catch (err) {
        
        if(err.extensions.response.status === 404) {
          return null;
        }
        throw err;
      }

This works but isn't particularly elegant for what seems to be a common use case. Have I misunderstood how to deal with 404 errors in GraphQL or is this part of the rest datasource that could have better handling around it?

I'd be interested to know how other people are dealing with this in a more elegant manor or at least encapsulating the null return inside the class which extends RESTDataSource. From skimming the code this didn't look easy to handle without rewriting some of the protected methods.

timReynolds avatar Oct 18 '18 19:10 timReynolds

I am also looking for best practices on this...

My current challenge is how to handle this during a server-side render(SSR). In the case of the REST API returning a 404, it causes a 404 error to be thrown, which then has to be handled within a catch statement. I have logic in the Query component for handling this behavior but during a SSR this logic is never hit because it throws exceptions instead.

Your solution is an option but painful like you said.

Another option, which I am not happy with, is setting the errorPolicy="all" on the Query component.

This causes the SSR to succeed and allows the apollo client to cache all the other successful responses. However, it then causes the client to re-issue the request and handle it accordingly, which results in the re-issuing same request the server already performed.

mikebm avatar Jan 23 '19 23:01 mikebm

I just ran into this myself, although in my case it was in the context of testing with an intentionally bad id for the API I'm hitting - i.e. expect(doTheThing(badId)).toThrow() or .toEqual(null) and the 404 was breaking it.

Here's a less painful version of the original solution, making use of the fact that await is just a fancy Promise:

return dataSources.listingApi.getListing(args.reference)
  .catch(err => {
    if(err.extensions.response.status === 404) {
      return null;
    }
      throw err;
    }
  })
  • Note that return await is unnecessary in an async function; you can just return the awaited expression.
  • This will get even shorter if throw expressions are added to ES (currently Stage 2, and available with Babel:
.catch(err => ((err.extensions.response.status === 404) ? null : throw err)

jalovatt avatar Oct 29 '19 18:10 jalovatt