Created
May 5, 2017 14:58
-
-
Save Izhaki/4a14a46836d906322a3cc9ced59f7f76 to your computer and use it in GitHub Desktop.
Client GraphQL Fetch ( Typescript )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as nock from 'nock' | |
import { | |
use, | |
expect, | |
} from 'chai' | |
import * as chaiAsPromised from 'chai-as-promised' | |
use( chaiAsPromised ) | |
import { | |
gqlFetch, | |
GqlError, | |
} from './gqlFetch' | |
const fetch = gqlFetch( '//localhost/graphql' ) | |
describe.only( `Client GraphQL Fetch`, () => { | |
it( `should post the query and provided variables`, () => { | |
const query = `{ | |
entities { | |
id | |
name | |
} | |
}` | |
const variables = { | |
name: 'Roey', | |
} | |
nock( 'https://localhost' ) | |
.post( `/graphql`, { query, variables } ) | |
.reply( 200, {} ) | |
return expect( fetch( query, variables ) ).to.be.fulfilled | |
}) | |
it( `should resolve the promise with the data provided in the GraphQL response`, () => { | |
const responseData = { | |
users: [{ | |
id: 0, | |
name: 'Roey', | |
}], | |
} | |
nock( 'https://localhost' ).post( `/graphql` ).reply( 200, { data: responseData } ) | |
return expect( fetch( '' ) ).to.eventually.deep.equal( responseData ) | |
}) | |
describe( `should return a rejected promise when`, () => { | |
beforeEach( () => { | |
this.nock = nock( 'https://localhost' ).post( `/graphql` ) | |
}) | |
it( `there was a network error`, () => { | |
this.nock.replyWithError( '' ) | |
return expect( fetch( '' ) ).to.be.rejectedWith( GqlError, 'Network error' ) | |
}) | |
it( `the http status is not succuss`, () => { | |
this.nock.reply( 400, '' ) | |
return expect( fetch( '' ) ).to.be.rejectedWith( GqlError, 'Http status error' ) | |
}) | |
it( `the json response could'nt be parsed`, () => { | |
this.nock.reply( 200, '{ Some invalid json' ) | |
return expect( fetch( '' ) ).to.be.rejectedWith( GqlError, 'Response parsing error' ) | |
}) | |
it( `the graphQL response has errors`, () => { | |
this.nock.reply( 200, { errors: [ 'GraphQL error' ] } ) | |
return expect( fetch( '' ) ).to.be.rejectedWith( GqlError, 'GraphQL error' ) | |
}) | |
}) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fetch from 'isomorphic-fetch' | |
type ApiResult = Promise<any> | |
export | |
class GqlError extends Error { | |
public response: any | |
public message: string | |
constructor( message: string, response: any ) { | |
super( message ) | |
this.response = response | |
} | |
public static throw( message: string, response: any ) { throw new GqlError( message , response ) } | |
} | |
const getDefaultHeaders = () => { | |
const headers = new Headers() | |
if ( !headers.get( 'content-type' ) ) { | |
headers.append( 'content-type', 'application/json' ) | |
} | |
return headers | |
} | |
// Based on graphql-fetch: https://github.com/tjmehta/graphql-fetch/blob/7bfe4deacde2c92935a73b52fac43ce43b8f11ab/index.js | |
const formatRequest = ( query: string, vars?: any, opts?: any ): Promise<any> => ({ | |
method: 'POST', | |
headers : getDefaultHeaders(), | |
body: JSON.stringify({ | |
query, | |
variables: vars || {}, | |
}), | |
// override the defaults above with the provided options | |
...opts, | |
}) | |
const networkError = ( error ) => { GqlError.throw( 'Network error', error ) } | |
const isHttpStatusSuccuss = ( status: number ): boolean => status >= 200 && status < 300 | |
const checkHttpStatus = ( response ): ApiResult => isHttpStatusSuccuss( response.status ) ? response : GqlError.throw( 'Http status error', response ) | |
const parseJson = ( response ): ApiResult => response.json().catch( ( error ) => { GqlError.throw( 'Response parsing error', error ) } ) | |
// GraphQl response will have an errors property if errors occured, but the promise returned will still resolve: | |
interface GqlResponse { | |
data?, | |
errors?, | |
} | |
// Upon errors, we want to reject the promise instead, and in case of resolve, we 'lift' the data property | |
const promisifyGqlResponse = ( response: GqlResponse ): ApiResult => response.errors ? GqlError.throw( 'GraphQL error', response ) : response.data | |
export | |
const gqlFetch = ( url: string ) => ( query: string, vars?: any, opts?: any ): ApiResult => | |
fetch( url, formatRequest( query, vars, opts )) | |
.catch( networkError ) | |
.then( checkHttpStatus ) | |
.then( parseJson ) | |
.then( promisifyGqlResponse ) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment