apollo-link-rest icon indicating copy to clipboard operation
apollo-link-rest copied to clipboard

Response status based on the response document

Open klarstrup opened this issue 5 years ago • 1 comments

So I have a case where my API server will give a status code 400 and internal error code 1501 on the response document meaning "invalid ID", ie.:

{
  "code": 1501,
  "id": "00jph2tpvxfrv8smz98rkee0ekd8oob1",
  "message": "Could not load catalog",
  "details": "Invalid resource id",
  "previous": null,
  "@note.1": "Hey! It looks like you found an error. If you have any questions about this error, feel free to contact support with the above error id."
}

As far as the web client is concerned, this is effectively a 404 and should be treated as such. But there is currently no convenient way of achieving this behavior in RestLink;

  • the responseTransformer is applied after the status reading and also only handles the response body
  • customFetch takes an extraordinary amount of jerry-rigging to get working both client-side and server-side getting this behavior(in fact I haven't managed).

So tl;dr, it would be nice to be able to either:

  • Inform RestLink of an alternative status code interpretation based on the response document
  • Take over status code handling entirely(as in, be allowed to inject an alternative implementation of this section: https://github.com/apollographql/apollo-link-rest/blob/5960abb3cae90bf1302654d39f6635d9f30df4cc/src/restLink.ts#L1011-L1044)
  • Or some other good idea someone might have to solve this quandary!

Hope this issue isn't too freeform 😅

klarstrup avatar Dec 09 '18 16:12 klarstrup

+1, great dive into this @klarstrup! Running into the same problem but in the other direction: a REST interface I can't modify returns 400's with a "message: (stringified JSON)" in the body, that indicates validation errors on a POST call from a mutation, etc. As it stands, I see no way to tell rest-link that's a GraphQL error rather than a network error. Have tried intercepting the response and mangling it with apollo-link-error, as well as rewriting that link itself.

I did put a hacky workaround in place using an apollo-link similar to apollo-link-error. Yours might look something like this:

const errorLink = new ApolloLink((operation, forward) => {
    return new Observable(observer => {
      let sub: ZenObservable.Subscription;

      try {
        sub = forward!(operation).subscribe({
          next: result => {
            if (result.code === 1501) {
                   observer.error(new Error('This is actually an error'));
            } else {
                   observer.next(result)
            }
          },
          error: networkError => {
              observer.error(networkError)
            }
          },
          complete: () => {
            observer.complete();
          },
        });
      } catch (e) {
        observer.error(e);
      }

      return () => {
        if (sub) sub.unsubscribe();
      };
    });
  });

It would be really great if we could provide a custom determineError() or similar method to link-rest. It does seem to me like the assumptions made in link-rest differ from those in the vanilla link-http.

I think by its nature, rest-link can't be as opinionated as the http-link. As the docs point out, in most use cases for link-rest, we can't change the backend. Thus, the response shapes and behavior won't fit any prescribed pattern, and there should be flexibility to decide whether a response is a GraphQL error, a network error, or no error at all.

If there's bandwidth to work with me on this, I can take on a PR.

Related: https://github.com/apollographql/apollo-link/issues/855

kalzoo avatar Jun 24 '19 17:06 kalzoo