Skip to content

Apollo и REST

Leonid Fenko edited this page Jul 15, 2019 · 3 revisions

REST должен использоваться только в случае крайней необходимости (например, требование заказчика). При этом обязательно надо рассмотреть возможность написания GraphQL-прослойки над REST.

Обработка ошибок

Необходимо конвертировать известные ошибки сети в GraphQL-ошибки. Умышленно или нет, Apollo обрабатывает их по-разному:

  • Ошибка сети прерывает getDataFromTree() даже при fetchPolicy: 'all'
  • Ошибка сети в <Query> родительского компонента приводит к игнорированию <Query> дочернего компонента (при SSR)

404

apollo-link-rest обрабатывает 404 ошибки специальным образом.

Пример конвертации ошибок

/** Number code, string code, like: [400, 'InvalidAuthDataError'] */
type NetworkError = [number, string];

interface ProcessableError {
    statusCode?: number;
    result: { code?: string; message?: string };
}

/** Converts given network errors to GraphQL errors */
function getErrorConverterLink(networkErrorList: NetworkError[]) {
    return new ApolloLink((operation, forward) => {
        return new Observable<FetchResult>(observer => {
            let sub: ZenObservable.Subscription;

            try {
                sub = forward!(operation).subscribe({
                    next(result) {
                        observer.next(result);
                    },
                    error(networkError) {
                        if (isNetworkErrorKnown(networkError, networkErrorList)) {
                            const processableError = networkError as ProcessableError;
                            observer.next({
                                errors: [
                                    new GraphQLError(
                                        processableError.result.message || 'Unknown network error',
                                        undefined,
                                        undefined,
                                        undefined,
                                        undefined,
                                        networkError,
                                        { code: processableError.result.code },
                                    ),
                                ],
                            });
                        }
                        observer.error(networkError);
                    },
                    complete: observer.complete.bind(observer),
                });
            } catch (e) {
                observer.error(e);
            }

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

function isNetworkErrorKnown(networkError: Error | null, networkErrorList: NetworkError[]) {
    return (
        !networkError ||
        (isProcessableError(networkError) &&
            networkErrorList.find(ignoreError => {
                const processableError = (networkError as unknown) as ProcessableError;
                return (
                    ignoreError[0] === processableError.statusCode && ignoreError[1] === processableError.result.code
                );
            }))
    );
}

function isProcessableError<T>(error: T | null): error is T & ProcessableError {
    return Boolean(error && (error as any).result);
}
Clone this wiki locally