-
Notifications
You must be signed in to change notification settings - Fork 16
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
Further fixes on pull #2 #3
base: master
Are you sure you want to change the base?
Changes from all commits
542243e
5178b2d
7efc6f3
099ed74
1a5dd54
64b2892
33bd2e3
1e991ae
c06f100
e784d1d
67fb4c5
9cfe90a
cf3376f
f59d66e
cf8f681
feff024
13519c3
a7c8941
1a6702e
a623834
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
MOCHA_TARGET=test/specs.js | ||
|
||
test: | ||
make testonly && make lint | ||
|
||
testonly: | ||
mocha $(MOCHA_TARGET) | ||
|
||
testonly-watch: | ||
mocha -w $(MOCHA_TARGET) | ||
|
||
lint: | ||
standard . | ||
|
||
.PHONY: test testonly testonly-watch lint |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,129 @@ | ||
function highlightQuery (query, errors) { | ||
var locations = errors.map(function (e) { return e.locations }) | ||
.reduce(function (a, b) { | ||
return a.concat(b) | ||
}, []) | ||
/* global fetch, Headers */ | ||
require('isomorphic-fetch') | ||
|
||
var queryHighlight = '' | ||
function Client (options) { | ||
var self = this | ||
|
||
query.split('\n').forEach(function (row, index) { | ||
var line = index + 1 | ||
var lineErrors = locations.filter(function (loc) { return loc.line === line }) | ||
if (!options.url) throw new Error('Missing url parameter') | ||
|
||
queryHighlight += row + '\n' | ||
self.options = options | ||
self.url = options.url | ||
|
||
if (lineErrors.length) { | ||
var errorHighlight = [] | ||
// A stack of registered listeners | ||
self.listeners = [] | ||
} | ||
|
||
lineErrors.forEach(function (line) { | ||
for (var i = 0; i < 8; i++) { | ||
errorHighlight[line.column + i] = '~' | ||
} | ||
}) | ||
// to reduce file size | ||
var proto = Client.prototype | ||
|
||
for (var i = 0; i < errorHighlight.length; i++) { | ||
queryHighlight += errorHighlight[i] || ' ' | ||
} | ||
queryHighlight += '\n' | ||
/** | ||
* Send a query and get a Promise | ||
* @param {String} query | ||
* @param {Object} variables | ||
* @param {Function} beforeRequest hook | ||
* @returns {Promise} | ||
*/ | ||
proto.query = function (query, variables, beforeRequest) { | ||
var self = this | ||
|
||
var req = self.options.request || {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should make this to an actual request object Fetch API Request. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed! Fixed this as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to switch back to plain req object since there were many problems with Request. For example, I couldn't pass headers to it when initializing the client because they could only be modified after the Request object is initialized. Also, I couldn't pass "credentials" to it, because of a bug in |
||
req.method || (req.method = 'POST') | ||
if (!req.headers) { | ||
req.headers = new Headers() | ||
req.headers.set('content-type', 'application/json') | ||
} | ||
req.body = JSON.stringify({ | ||
query: query, | ||
variables: variables | ||
}) | ||
|
||
// 'beforeRequest' is a top priority per-query hook, it should forcibly | ||
// override response even from other hooks. | ||
var result = beforeRequest && beforeRequest(req) | ||
|
||
if (typeof result === 'undefined') { | ||
result = self.emit('request', req) | ||
|
||
// No 'response' hook here, reserve it for real responses only. | ||
|
||
// 'data' hook is only triggered if there are any data | ||
if (typeof result !== 'undefined') { | ||
var data = self.emit('data', result, true) // `true` for fake data | ||
if (typeof data !== 'undefined') result = data | ||
} | ||
} | ||
|
||
if (typeof result !== 'undefined') { | ||
result = Promise.resolve(result) | ||
} | ||
return result || self.fetch(req) | ||
} | ||
|
||
/** | ||
* For making requests | ||
* @param {Object} req | ||
* @returns Promise | ||
*/ | ||
proto.fetch = function (req) { | ||
var self = this | ||
|
||
return fetch(self.url, req).then(function (res) { | ||
// 'response' hook can redefine `res` | ||
var _res = self.emit('response', res) | ||
if (typeof _res !== 'undefined') res = _res | ||
|
||
return res.json() | ||
}).then(function (data) { | ||
// 'data' hook can redefine `data` | ||
var _data = self.emit('data', data) | ||
if (typeof _data !== 'undefined') data = _data | ||
|
||
return data | ||
}) | ||
} | ||
|
||
/** | ||
* Register a listener. | ||
* @param {String} eventName - 'request', 'response', 'data' | ||
* @param {Function} callback | ||
* @returns Client instance | ||
*/ | ||
proto.on = function (eventName, callback) { | ||
var allowedNames = ['request', 'response', 'data'] | ||
|
||
if (~allowedNames.indexOf(eventName)) { | ||
this.listeners.push([ eventName, callback ]) | ||
} | ||
|
||
return queryHighlight | ||
return this | ||
} | ||
|
||
module.exports = function (params) { | ||
require('isomorphic-fetch') | ||
if (!params.url) throw new Error('Missing url parameter') | ||
|
||
return { | ||
query: function (query, variables) { | ||
var headers = new Headers() | ||
headers.append('Content-Type', 'application/json') | ||
|
||
return fetch(params.url, { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
query: query, | ||
variables: variables | ||
}), | ||
headers: headers, | ||
credentials: params.credentials | ||
}).then(function (res) { | ||
return res.json() | ||
}).then(function (data) { | ||
if (data.errors && data.errors.length) { | ||
throw new Error(data.errors.map(function (e) { return e.message }).join('\n') + '\n' + highlightQuery(query, data.errors)) | ||
} | ||
return data | ||
}) | ||
/** | ||
* Emit an event. | ||
* @param {String} eventName - 'request', 'response', 'data' | ||
* @param {mixed} ...args | ||
* @returns {Array} array of results received from each listener respectively | ||
*/ | ||
proto.emit = function (eventName) { | ||
var args = Array.prototype.slice.call(arguments, 1) | ||
var listeners = this.listeners | ||
var result | ||
|
||
// Triggering listeners and gettings latest result | ||
for (var i = 0; i < listeners.length; i++) { | ||
if (listeners[i][0] === eventName) { | ||
var r = listeners[i][1].apply(this, args) | ||
if (typeof r !== 'undefined') { | ||
result = r | ||
} | ||
} | ||
} | ||
|
||
return result | ||
} | ||
|
||
module.exports = function (options) { | ||
return new Client(options) | ||
} | ||
|
||
module.exports.Client = Client |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
const { | ||
GraphQLSchema, | ||
GraphQLObjectType, | ||
GraphQLString | ||
} = require('graphql') | ||
|
||
const data = [ | ||
{ id: '1', name: 'Dan' }, | ||
{ id: '2', name: 'Marie' }, | ||
{ id: '3', name: 'Jessie' } | ||
] | ||
|
||
const userType = new GraphQLObjectType({ | ||
name: 'User', | ||
fields: { | ||
id: { type: GraphQLString }, | ||
name: { type: GraphQLString } | ||
} | ||
}) | ||
|
||
const schema = new GraphQLSchema({ | ||
query: new GraphQLObjectType({ | ||
name: 'Query', | ||
fields: { | ||
user: { | ||
type: userType, | ||
args: { | ||
id: { type: GraphQLString } | ||
}, | ||
resolve: (_, args) => data.find((u) => u.id === args.id) | ||
} | ||
} | ||
}) | ||
}) | ||
|
||
module.exports = schema |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
const http = require('http') | ||
const schema = require('./schema') | ||
const { graphql } = require('graphql') | ||
|
||
module.exports = http.createServer((req, res) => { | ||
if (req.url === '/graphql') { | ||
let body = '' | ||
|
||
req.on('data', function (data) { | ||
body += data | ||
}) | ||
|
||
req.on('end', function () { | ||
let query = body | ||
let variables | ||
let operationName | ||
|
||
if (~req.headers['content-type'].indexOf('application/json')) { | ||
try { | ||
const obj = JSON.parse(query) | ||
if (obj.query && typeof obj.query === 'string') { | ||
query = obj.query | ||
} | ||
if (obj.variables !== undefined) { | ||
variables = obj.variables | ||
} | ||
// Name of GraphQL operation to execute. | ||
if (typeof obj.operationName === 'string') { | ||
operationName = obj.operationName | ||
} | ||
} catch (err) { | ||
// do nothing | ||
} | ||
} | ||
|
||
res.writeHead(200, {'content-type': 'text/json'}) | ||
|
||
graphql(schema, query, null, variables, operationName).then((result) => { | ||
let response = result | ||
|
||
if (result.errors) { | ||
res.statusCode = 400 | ||
response = { | ||
errors: result.errors.map(String) | ||
} | ||
} | ||
|
||
res.end(JSON.stringify(response)) | ||
}).catch((e) => { | ||
res.end(JSON.stringify(e)) | ||
}) | ||
}) | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove Makefile
use npm scripts
https://www.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/