Skip to content

Instantly share code, notes, and snippets.

@feliperohdee
Last active January 31, 2018 12:18
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 feliperohdee/43e9b2979e93003c0f71fb52e06d1049 to your computer and use it in GitHub Desktop.
Save feliperohdee/43e9b2979e93003c0f71fb52e06d1049 to your computer and use it in GitHub Desktop.
Multiplex many GraphQL requests
/*
Usage:
const http = json => fetch('http://yourGraphQLEndpoint.com', {
method: 'POST',
cache: 'no-store',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(json)
});
const queue = new GraphQLMux(http, 'query', 10);
queue.graphql({
requestString: `query($user: String!) {
user(id: $user) {
name
}
}`
})
.then(...);
queue.graphql({
requestString: `query(order: String!) {
order(id: $order) {
date
total
}
}`
})
.then(...);
*/
import isUndefined from 'lodash/isUndefined';
import reduce from 'lodash/reduce';
import trim from 'lodash/trim';
import {
cuid
} from '../utils';
const definitionsRegex = /\$\w+:\s*[^$,)]*/g;
const extractInnerRegex = /\{(.*)\}/g;
const reduceStringRegex = /\s{2,}/g;
export default class GraphQLMux {
constructor(executor, type = 'query', wait = 10) {
this.setup();
this.executor = executor;
this.type = type;
this.wait = wait;
}
setup() {
this.resolvers = [];
this.rejecters = [];
this.definitions = {};
this.requestString = [];
this.variableValues = {};
}
graphql({
requestString = '',
variableValues = {}
}) {
clearTimeout(this.timeout);
const id = cuid();
const definitions = reduce(requestString.match(definitionsRegex), (reduction, token) => {
const [
key,
value
] = token.split(':');
return {
...reduction,
[trim(key)]: trim(value)
};
}, {});
requestString = requestString.replace(reduceStringRegex, ' ');
requestString = requestString.match(extractInnerRegex)[0];
requestString = trim(requestString, /\{\}/g);
this.variableValues = reduce(variableValues, (reduction, value, key) => {
if (!isUndefined(value)) {
reduction[`${key}_${id}`] = value;
requestString = requestString.replace(new RegExp(`\\$${key}`, 'g'), `$${key}_${id}`);
}
return reduction;
}, this.variableValues);
this.definitions = reduce(definitions, (reduction, value, key) => {
const hasVariable = !isUndefined(this.variableValues[`${key.slice(1)}_${id}`]);
reduction[hasVariable ? `${key}_${id}` : key] = value;
return reduction;
}, this.definitions);
this.requestString = this.requestString.concat(requestString);
this.timeout = setTimeout(() => {
const resolvers = [].concat(this.resolvers);
const rejecters = [].concat(this.rejecters);
const definitions = reduce(this.definitions, (reduction, value, key) => {
return reduction.concat(`${key}:${value}`);
}, [])
.join();
this.executor({
requestString: `${this.type}${definitions ? `(${definitions})` : ''} {${this.requestString.join('\n')}}`,
variableValues: this.variableValues
})
.then(response => {
while (resolvers.length > 0) {
resolvers.shift()(response);
}
})
.catch(err => {
while (rejecters.length > 0) {
rejecters.shift()(err);
}
});
this.setup();
}, this.wait);
return new Promise((resolve, reject) => {
this.resolvers.push(resolve);
this.rejecters.push(reject);
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment