From b9fb36d4b7e36f8a5d68cde92672a249775d45bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Lach=C3=A8ze?= Date: Wed, 23 Jan 2019 21:45:07 +0100 Subject: [PATCH 1/2] Better handle errors report by reactive-graphql --- src/__tests__/reactiveSchemaLink.ts | 60 ++++++++++++++++++----------- src/reactiveSchemaLink.ts | 30 ++++++++++++--- 2 files changed, 63 insertions(+), 27 deletions(-) diff --git a/src/__tests__/reactiveSchemaLink.ts b/src/__tests__/reactiveSchemaLink.ts index a715496..b227e44 100644 --- a/src/__tests__/reactiveSchemaLink.ts +++ b/src/__tests__/reactiveSchemaLink.ts @@ -1,10 +1,25 @@ -import { execute } from 'apollo-link'; +import { execute, Observable } from 'apollo-link'; import { from } from "rxjs"; import { makeExecutableSchema } from 'graphql-tools'; import gql from 'graphql-tag'; +import { graphql } from 'graphql'; import { ReactiveSchemaLink } from '../reactiveSchemaLink'; +/** + * Take an Observable and return a Promise that is resolved with and on the + * first value emited. + */ +function toPromise(obs: Observable): Promise { + return new Promise((resolve, reject) => { + obs.subscribe({ + next: resolve, + error: reject, + }) + }) +} + + const sampleQuery = gql` query SampleQuery { sampleQuery { @@ -98,27 +113,6 @@ describe('ReactiveSchemaLink', () => { }); }); - it('calls error when fetch fails', done => { - const badTypeDefs = 'type Query {}'; - const badSchema = makeExecutableSchema({ typeDefs }); - - const link = new ReactiveSchemaLink({ schema: badSchema }); - const observable = execute(link, { - query: sampleQuery, - }); - observable.subscribe( - result => expect(false), - error => { - expect(error).toBeDefined(); - done(); - }, - () => { - expect(false); - done(); - }, - ); - }); - it('pass down variables', done => { const next = jest.fn(); const sampleQueryWithArgsResolver = jest.fn() @@ -182,4 +176,26 @@ describe('ReactiveSchemaLink', () => { }, }); }); + + + it('adds an error in erros when a resolver fail', async () => { + const resolvers = { + Query: { + sampleQuery: (root, args, context) => { + throw new Error('Bip bip'); + } + } + } + const schema = makeExecutableSchema({ + typeDefs, + resolvers + }); + + const link = new ReactiveSchemaLink({ schema }); + const results = await toPromise(execute(link, { + query: sampleQuery, + })); + + expect(results.errors).toHaveLength(1); + }) }); diff --git a/src/reactiveSchemaLink.ts b/src/reactiveSchemaLink.ts index a3911cf..aa5550a 100644 --- a/src/reactiveSchemaLink.ts +++ b/src/reactiveSchemaLink.ts @@ -1,6 +1,8 @@ import { ApolloLink, Operation, FetchResult, Observable } from 'apollo-link'; -import { GraphQLSchema } from 'graphql'; +import { GraphQLSchema, GraphQLError } from 'graphql'; import { graphql } from 'reactive-graphql'; +import { of } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; export namespace ReactiveSchemaLink { export type ResolverContextFunction = ( @@ -20,6 +22,23 @@ export namespace ReactiveSchemaLink { } } +// will transform the errors of the execution results provided by +// reactive-graphql in proper GraphQLErrors +function normalizeErrorsField(results: {data?: object, errors?: string[]}): FetchResult { + const _results: FetchResult = {}; + _results.data = results.data; + if (results.errors) { + _results.errors = results.errors.map(message => { + // @ts-ignore just to be sure, message could be an instance of error + if (typeof message.message === 'string') { + // @ts-ignore + return new GraphQLError(message.message); + } + return new GraphQLError(message); + }); + } + return _results; +} export class ReactiveSchemaLink extends ApolloLink { public schema: GraphQLSchema; public context: ReactiveSchemaLink.ResolverContextFunction | any; @@ -42,11 +61,12 @@ export class ReactiveSchemaLink extends ApolloLink { null, context, operation.variables, - // @ts-ignore issue with the typage of the `errors` key in reactive-graphql - // https://github.com/mesosphere/reactive-graphql/pull/11/files#r249788225 - ).subscribe(observer); + ) + .pipe(catchError((error: Error) => of({errors: [new GraphQLError(error.message)] }))) + .pipe(map(normalizeErrorsField)) + .subscribe(observer); } catch(e) { - observer.error(e); + observer.next({ errors: [new GraphQLError(e.mesage)]}); } }); } From 2dd0efc68f6da5105fce456500d7dcd57124ec85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20Lach=C3=A8ze?= Date: Wed, 23 Jan 2019 21:46:55 +0100 Subject: [PATCH 2/2] remove unused import --- src/__tests__/reactiveSchemaLink.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/__tests__/reactiveSchemaLink.ts b/src/__tests__/reactiveSchemaLink.ts index b227e44..dc005ea 100644 --- a/src/__tests__/reactiveSchemaLink.ts +++ b/src/__tests__/reactiveSchemaLink.ts @@ -2,7 +2,6 @@ import { execute, Observable } from 'apollo-link'; import { from } from "rxjs"; import { makeExecutableSchema } from 'graphql-tools'; import gql from 'graphql-tag'; -import { graphql } from 'graphql'; import { ReactiveSchemaLink } from '../reactiveSchemaLink';