Skip to content

Instantly share code, notes, and snippets.

@Izhaki
Created May 5, 2017 14:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Izhaki/4a14a46836d906322a3cc9ced59f7f76 to your computer and use it in GitHub Desktop.
Save Izhaki/4a14a46836d906322a3cc9ced59f7f76 to your computer and use it in GitHub Desktop.
Client GraphQL Fetch ( Typescript )
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' )
})
})
})
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