Skip to content

Commit

Permalink
fix: Graphql Options endpoint for routing
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasdao committed Aug 11, 2017
1 parent f8fe8bb commit ff9ba53
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 22 deletions.
38 changes: 20 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const parseBody = require('./parseBody')
const renderGraphiQL = require('./renderGraphiQL')

const mergeGraphqlOptionsWithEndpoint = (graphqlOptions = {}, endpointPath = '/') =>
graphqlOptions.endpointURL && !graphqlOptions.endpointURLAlreadyModified
? Object.assign(graphqlOptions, { endpointURL: path.join(endpointPath, graphqlOptions.endpointURL), endpointURLAlreadyModified: true })
graphqlOptions.endpointURL
? Object.assign({}, graphqlOptions, { endpointURL: path.join(endpointPath, graphqlOptions.endpointURL) })
: graphqlOptions

exports.serveHTTP = (arg1, arg2, arg3) => {
Expand All @@ -43,17 +43,17 @@ exports.serveHTTP = (arg1, arg2, arg3) => {

if (arg1) {
if (typeOfArg1 != 'string' && typeOfArg1 != 'object' && typeOfArg1 != 'function')
throw new Error('The first argument of the \'serveHTTP\' method can only be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('The first argument of the \'serveHTTP\' method can only be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')

if (typeOfArg1 == 'string') {
route = arg1
routeDetails = routing.getRouteDetails(route)
if (!arg2)
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument is required and must either be a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument is required and must either be a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')
if (typeOfArg2 != 'object' && typeOfArg2 != 'function')
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument must either be a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument must either be a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')
if (typeOfArg2 == 'object' && arg2.length >= 0)
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument of the \'serveHTTP\' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('If the first argument of the \'serveHTTP\' method is a route, then the second argument of the \'serveHTTP\' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')
if (typeOfArg2 == 'object' && !arg2.schema)
throw new Error('If the first argument of the \'serveHTTP\' method is a route and the second a graphQL object, then the second argument must contain a valid property called \'schema\'.')

Expand All @@ -64,7 +64,7 @@ exports.serveHTTP = (arg1, arg2, arg3) => {
}
else {
if (arg1.length != undefined)
throw new Error('The first argument of the \'serveHTTP\' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('The first argument of the \'serveHTTP\' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')
if (typeOfArg1 == 'object' && !arg1.schema)
throw new Error('If the first argument of the \'serveHTTP\' method is a graphQL object, then it must contain a valid property called \'schema\'.')

Expand All @@ -74,31 +74,33 @@ exports.serveHTTP = (arg1, arg2, arg3) => {
appConfig = arg2
}

const optionType = typeof(getOptions)
const getNewOptions = optionType == 'object'
? () => Promise.resolve(getOptions) :
optionType == 'function' ? (req, res, params) => Promise.resolve(getOptions(req, res, params)) :
() => Promise.resolve({})

const func = (req, res, params) => {
const httpEndpoint = ((req._parsedUrl || {}).pathname || '/').toLowerCase()
const endpoint = routeDetails ? ((routing.matchRoute(httpEndpoint, routeDetails) || {}).match || '/') : '/'
if (!res.headersSent) {
if (!getOptions)
throw httpError(500, 'GraphQL middleware requires getOptions.')
else {
const optionType = typeof(getOptions)
const getHttpHandler =
optionType == 'object' ? Promise.resolve(graphqlHTTP(mergeGraphqlOptionsWithEndpoint(getOptions, endpoint))) :
optionType == 'function' ? getOptions(req, res, params).then(options => !res.headersSent ? graphqlHTTP(mergeGraphqlOptionsWithEndpoint(options, endpoint)) : null) :
null

if (!getHttpHandler)
throw httpError(500, `GraphQL middleware requires a valid 'getOptions' argument(allowed types: 'object', 'function'). Type '${typeof(getOptions)}' is invalid.`)

return getHttpHandler.then(httpHandler => httpHandler(req, res))
const getHttpHandler = getNewOptions(req, res, params).then(options => !res.headersSent ? graphqlHTTP(mergeGraphqlOptionsWithEndpoint(options, endpoint)) : null)
return getHttpHandler.then(httpHandler => {
if (!httpHandler)
throw httpError(500, 'GraphQL middleware requires a valid \'getOptions\' argument.')
return httpHandler(req, res)
})
}
}
}

return route ? serveHttp(route, func, appConfig) : serveHttp(func, appConfig)
}
else
throw new Error('The first argument of the \'serveHTTP\' method is required. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.')
throw new Error('The first argument of the \'serveHTTP\' method is required. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.')
}

exports.graphqlHTTP = graphqlHTTP
Expand Down
24 changes: 20 additions & 4 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ describe('index', () =>

const endpoints = [1,2]

assert.throws(() => serveHTTP('/users/{username}', endpoints, appconfig), Error, `If the first argument of the 'serveHTTP' method is a route, then the second argument of the 'serveHTTP' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.`)
assert.throws(() => serveHTTP('/users/{username}', endpoints, appconfig), Error, `If the first argument of the 'serveHTTP' method is a route, then the second argument of the 'serveHTTP' method cannot be an array. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.`)
assert.throws(() => serveHTTP('/users/{username}', appconfig), Error, `If the first argument of the 'serveHTTP' method is a route and the second a graphQL object, then the second argument must contain a valid property called 'schema'.`)
assert.throws(() => serveHTTP(), Error, `The first argument of the 'serveHTTP' method is required. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a promise containing a graphQL option object.`)
assert.throws(() => serveHTTP(), Error, `The first argument of the 'serveHTTP' method is required. It must either be a route, a graphQL options object, or a function similar to (req, res, params) => ... that returns a graphQL option object or a promise returning a graphql object.`)
assert.throws(() => serveHTTP(appconfig), Error, `If the first argument of the 'serveHTTP' method is a graphQL object, then it must contain a valid property called 'schema'.`)
})))

Expand Down Expand Up @@ -79,10 +79,21 @@ describe('index', () =>
referer: 'http://localhost:8080'
},
_parsedUrl: {
pathname: '/users/graphiql'
pathname: '/users/nicolas/graphiql'
}
})
const res_01 = httpMocks.createResponse()
const req_02 = httpMocks.createRequest({
method: 'GET',
headers: {
origin: 'http://localhost:8080',
referer: 'http://localhost:8080'
},
_parsedUrl: {
pathname: '/users/brendan/graphiql'
}
})
const res_02 = httpMocks.createResponse()

const appconfig = {
headers: {
Expand All @@ -93,13 +104,18 @@ describe('index', () =>
}
}

const fn = serveHTTP('/users', { schema: {} }, appconfig)
const fn = serveHTTP('/users/{username}', { schema: {}, endpointURL: '/graphiql' }, appconfig)

const result_01 = fn(req_01, res_01).then(() => {
assert.equal(1,1)
})
.catch(() => assert.equal(1,2, `This request should have succeeded.`))

const result_02 = fn(req_02, res_02).then(() => {
assert.equal(1,1)
})
.catch(() => assert.equal(1,2, `This request should have succeeded.`))

return Promise.all([result_01])
})))

Expand Down

0 comments on commit ff9ba53

Please sign in to comment.