Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(graphql): 补充简单的 errors 字段处理机制 #551

Merged
merged 1 commit into from
Sep 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/SDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class SDK {
}
}

graph<T extends object>(query: string, variables: Variables, withHeaders: true): Observable<T & { headers: Headers }>
graph<T extends object>(query: string, variables: Variables, withHeaders: false): Observable<T>
graph<T extends object>(query: string, variables?: Variables): Observable<T>
graph<T extends object>(query: string): Observable<T>
graph<T extends object>(query: string, variables?: Variables, withHeaders: boolean = false) {
if (this.graphQLClientOption == null) {
throw Error('GraphQL server should be specified.')
Expand All @@ -77,11 +81,12 @@ export class SDK {
{ ...this.graphQLClientOption, includeHeaders: true }
)
.map(({ headers, body }) => {
if (withHeaders) {
const data: object = body.data
return ({ ...data, headers: headers })
const { errors, data } = body
if (errors) {
const errmsg = errors.map(({ message }) => `${message}`)
throw new Error(errmsg.join('\n'))
}
return body.data
return withHeaders ? { ...(data! as any), headers } : data!
})
}

Expand Down
15 changes: 12 additions & 3 deletions src/utils/internalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,18 @@ export interface GraphQLRequestContext {
variables?: Variables
}

export interface GraphQLResponse<T = any> {
data: T
errors?: Error[]
// see: http://facebook.github.io/graphql/June2018/#sec-Errors
export type GraphQLError = {
message: string
path?: Array<string | number>
locations?: Array<{ line: number, column: number }>
extensions?: { [key: string ]: any }
}

// see: http://facebook.github.io/graphql/June2018/#sec-Response-Format
export interface GraphQLResponse<T = { [key: string]: any }> {
data?: T | null // see: http://facebook.github.io/graphql/June2018/#sec-Data
errors?: GraphQLError[] // see: http://facebook.github.io/graphql/June2018/#sec-Errors
extensions?: any
status: number
[key: string]: any
Expand Down
56 changes: 55 additions & 1 deletion test/SDKFetch.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai'
import { Observable, Scheduler } from 'rxjs'
import { describe, it, beforeEach, afterEach } from 'tman'
import { SDKFetch, forEach, Http, HttpErrorMessage, headers2Object } from '.'
import { SDK, SDKFetch, forEach, Http, HttpErrorMessage, headers2Object, createSdk } from '.'
import { clone } from './'

import { defaultSDKFetchHeaders, HttpHeaders } from '../src/SDKFetch'
Expand Down Expand Up @@ -499,6 +499,60 @@ describe('SDKFetch options', () => {

})

describe('graphql request/response', () => {
let sdk: SDK
let errorThrown: boolean
const url = 'https://www.example.com/graphql'

beforeEach(() => {
sdk = createSdk()
sdk.fetch.setAPIHost('https://www.example.com')
sdk.setGraphQLEndpoint('graphql')
errorThrown = false
})

afterEach(() => {
fetchMock.restore()
})

it('should throw error on failed HTTP connection', function* () {
fetchMock.mock(new RegExp(url), { status: 404 })
yield sdk.graph('')
.catch((info: HttpErrorMessage) => {
expect(info.error.status).to.equal(404)
errorThrown = true
return Observable.empty()
})
.subscribeOn(Scheduler.asap)
expect(errorThrown).to.be.true
})

it('should throw error on failed backend execution', function* () {
fetchMock.mock(new RegExp(url), {
data: {}, // data 与 errors 字段根据标准是可以同时存在的
errors: [{ message: 'error!' }, { message: 'sorry!' }]
})
yield sdk.graph('')
.catch((info) => {
expect(info.message).to.equal(`error!\nsorry!`)
errorThrown = true
return Observable.empty()
})
.subscribeOn(Scheduler.asap)
expect(errorThrown).to.be.true
})

it('should emit `data` when `errors` is not present', function* () {
const data = { recommend: { organization: { _id: '123', name: 'test' } } }
fetchMock.mock(new RegExp(url), { data })
yield sdk.graph('')
.do((resp) => {
expect(resp).to.deep.equal(data)
})
.subscribeOn(Scheduler.asap)
})
})

describe('HttpHeaders', () => {
it(`${HttpHeaders.create.name}() should normalize 'headers': key -> lower-case, value -> string`, () => {
expect(HttpHeaders.create({ 'AbCd': 14 }, { disableRequestId: true }))
Expand Down