Skip to content

Commit 975053c

Browse files
authored
Merge pull request #9 from marmelab/put_it_all_together
[RFR] Working fake server
2 parents 411dda9 + 6fc4a5d commit 975053c

23 files changed

+1090
-230
lines changed

Makefile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ build: clean ## Compile ES6 files to JS
1616
NODE_ENV=development ./node_modules/.bin/rollup -c
1717

1818
watch: ## continuously compile ES6 files to JS
19-
@NODE_ENV=production ./node_modules/.bin/babel \
20-
--out-dir=lib \
21-
--ignore='*.test.js' \
22-
--watch \
23-
./src
19+
NODE_ENV=development ./node_modules/.bin/rollup -c --watch
2420

2521
test: ## Launch unit tests
2622
@./node_modules/.bin/jest

bin/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env node
2+
var path = require('path');
3+
var JsonGraphqlServer = require('./../lib/');
4+
var express = require('express');
5+
6+
var dataFilePath = process.argv.length > 2 ? process.argv[2] : './data.json';
7+
var data = require(path.join(process.cwd(), dataFilePath));
8+
var PORT = 3000;
9+
var app = express();
10+
11+
app.use('/', JsonGraphqlServer.jsonGraphqlExpress(data));
12+
app.listen(PORT);
13+
var msg = `GraphQL server running with your data at http://localhost:${PORT}/`;
14+
console.log(msg); // eslint-disable-line no-console

example/index.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
],
3333
};
3434

35-
var server = JsonGraphqlServer.GraphQLClientServer(data);
35+
var server = JsonGraphqlServer.graphQLClientServer(data);
3636

3737
var xhr = new XMLHttpRequest();
3838
xhr.responseType = 'json';
@@ -43,9 +43,10 @@
4343
console.error(error);
4444
}
4545
xhr.onload = function() {
46-
console.log('data returned:', xhr.response);
46+
console.log('data returned:', JSON.parse(xhr.responseText));
4747
}
48-
xhr.send(JSON.stringify({query: "{ hello }"}));
48+
const body = JSON.stringify({ query: 'query Post($id: ID!) { Post(id: $id) { id } }', variables: { id: 1 } });
49+
xhr.send(body);
4950
});
5051
</script>
5152
</body>

package.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,19 @@
3838
"eslint-plugin-import": "~2.7.0",
3939
"eslint-plugin-jest": "~20.0.3",
4040
"eslint-plugin-prettier": "~2.1.2",
41+
"express": "~4.15.3",
4142
"husky": "~0.13.3",
4243
"jest": "~20.0.4",
4344
"lint-staged": "~3.4.1",
4445
"prettier": "~1.5.2",
4546
"rollup": "~0.43.0",
4647
"rollup-plugin-babel": "~2.7.1",
4748
"rollup-plugin-commonjs": "~8.0.2",
49+
"rollup-plugin-json": "~2.3.0",
4850
"rollup-plugin-node-builtins": "~2.1.2",
51+
"rollup-plugin-node-globals": "~1.1.0",
4952
"rollup-plugin-node-resolve": "~3.0.0",
50-
"rollup-plugin-replace": "~1.1.1"
53+
"rollup-watch": "~4.0.0"
5154
},
5255
"dependencies": {
5356
"apollo-client": "~1.2.0",
@@ -58,8 +61,10 @@
5861
"graphql-server-express": "~1.0.0",
5962
"graphql-tag": "~2.0.0",
6063
"graphql-tools": "~1.1.0",
61-
"inflection": "^1.12.0",
62-
"lodash.merge": "~4.6.0",
63-
"sinon": "~2.3.6"
64+
"inflection": "~1.12.0",
65+
"lodash.merge": "~4.6.0"
66+
},
67+
"bin": {
68+
"json-graphql-server": "bin/index.js"
6469
}
6570
}

rollup.config.js

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,22 @@ import resolve from 'rollup-plugin-node-resolve';
22
import commonjs from 'rollup-plugin-commonjs';
33
import babel from 'rollup-plugin-babel';
44
import builtins from 'rollup-plugin-node-builtins';
5-
import replace from 'rollup-plugin-replace';
5+
import globals from 'rollup-plugin-node-globals';
6+
import json from 'rollup-plugin-json';
67

78
export default {
89
entry: './src/index.js',
910
dest: 'lib/index.js',
1011
format: 'umd',
1112
moduleName: 'JsonGraphqlServer',
1213
plugins: [
13-
replace({
14-
'process.env.NODE_ENV': JSON.stringify('production'),
15-
'process.env.GRAPHQL_NO_NAME_WARNING': JSON.stringify(false),
16-
'process.env': JSON.stringify(true),
17-
process: JSON.stringify(true),
18-
}),
19-
builtins(),
2014
resolve({
15+
jsnext: true,
2116
browser: true,
2217
}),
2318
commonjs({
2419
include: 'node_modules/**',
20+
exclude: 'node_modules/rollup-plugin-node-builtins/**',
2521
namedExports: {
2622
'node_modules/graphql-tools/dist/index.js': [
2723
'addMockFunctionsToSchema',
@@ -30,9 +26,29 @@ export default {
3026
'node_modules/apollo-test-utils/dist/src/index.js': [
3127
'mockNetworkInterfaceWithSchema',
3228
],
33-
'node_modules/graphql/index.js': ['graphql'],
29+
'node_modules/graphql/index.js': [
30+
'graphql',
31+
'GraphQLBoolean',
32+
'GraphQLFloat',
33+
'GraphQLID',
34+
'GraphQLInt',
35+
'GraphQLList',
36+
'GraphQLNonNull',
37+
'GraphQLObjectType',
38+
'GraphQLSchema',
39+
'GraphQLString',
40+
],
41+
'node_modules/inflection/lib/inflection.js': [
42+
'camelize',
43+
'pluralize',
44+
'singularize',
45+
'underscore',
46+
],
3447
},
3548
}),
49+
builtins(),
50+
globals(),
51+
json(),
3652
babel({
3753
runtimeHelpers: true,
3854
exclude: 'node_modules/**', // only transpile our source code

src/createApolloClient.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { ApolloClient } from 'apollo-client';
22
import { mockNetworkInterfaceWithSchema } from 'apollo-test-utils';
3-
import getSchemaFromData from './getSchemaFromData';
3+
import getSchemaFromData from './introspection/getSchemaFromData';
44

5-
export default function(data) {
5+
export default data => {
66
const schema = getSchemaFromData(data);
77
const mockNetworkInterface = mockNetworkInterfaceWithSchema({ schema });
88

@@ -11,4 +11,4 @@ export default function(data) {
1111
});
1212

1313
return client;
14-
}
14+
};

src/getSchemaFromData.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/graphQLClientServer.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { useFakeXMLHttpRequest } from 'sinon';
1+
import { MockHttpServer } from './mockHttpRequest';
22
import { graphql } from 'graphql';
3-
import getSchemaFromData from './getSchemaFromData';
3+
import getSchemaFromData from './introspection/getSchemaFromData';
44

55
/**
66
* Starts a GraphQL Server in your browser: intercepts every call to http://localhost:3000/graphql
@@ -44,30 +44,31 @@ import getSchemaFromData from './getSchemaFromData';
4444
export default function(data, url = 'http://localhost:3000/graphql') {
4545
const schema = getSchemaFromData(data);
4646

47-
const fakeXhr = useFakeXMLHttpRequest();
48-
fakeXhr.useFilters = true;
49-
fakeXhr.addFilter((method, xhrUrl) => {
50-
return !xhrUrl.startsWith(url);
51-
});
47+
const server = new MockHttpServer(req => {
48+
if (!req.url.startsWith(url)) {
49+
// FIXME: if req.url does not match url for endpoint, handle it with window.OriginalHttpRequest
50+
}
5251

53-
fakeXhr.onCreate = xhr => {
54-
const query = xhr.requestBody;
52+
const query = JSON.parse(req.requestText);
5553

56-
graphql(schema, query).then(
54+
graphql(
55+
schema,
56+
query.query,
57+
undefined,
58+
undefined,
59+
query.variables,
60+
).then(
5761
result => {
58-
xhr.respond(
59-
200,
60-
{ 'Content-Type': 'application/json' },
61-
JSON.stringify(result),
62-
);
62+
const body = JSON.stringify(result);
63+
req.setResponseHeader('Content-Type', 'application/json');
64+
req.receive(200, body);
6365
},
6466
error => {
65-
xhr.respond(
66-
500,
67-
{ 'Content-Type': 'application/json' },
68-
JSON.stringify(error),
69-
);
67+
req.setResponseHeader('Content-Type', 'application/json');
68+
req.receive(500, JSON.stringify(error));
7069
},
7170
);
72-
};
71+
});
72+
73+
server.start();
7374
}

src/index.js

Lines changed: 2 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,143 +1,3 @@
1-
import { makeExecutableSchema, addMockFunctionsToSchema } from 'graphql-tools';
2-
import pluralize from 'pluralize';
31
export { default as createApolloClient } from './createApolloClient';
4-
export { default as GraphQLClientServer } from './graphQLClientServer';
5-
6-
export default function() {
7-
const typeDefs = {};
8-
const schema = makeExecutableSchema({ typeDefs });
9-
10-
const currentData = {};
11-
12-
const mockQueriesForEntity = entity => {
13-
const entityData = currentData[pluralize(entity).toLowerCase()];
14-
15-
return {
16-
[`getPageOf${pluralize(entity)}`]: (
17-
r,
18-
{ page, perPage, filter },
19-
) => {
20-
const filters = JSON.parse(filter);
21-
let items = entityData;
22-
23-
if (filters.ids) {
24-
items = items.filter(d =>
25-
filters.ids.includes(d.id.toString()),
26-
);
27-
} else {
28-
Object.keys(filters)
29-
.filter(key => key !== 'q')
30-
.forEach(key => {
31-
if (key.indexOf('_lte') !== -1) {
32-
// less than or equal
33-
const realKey = key.replace(/(_lte)$/, '');
34-
items = items.filter(
35-
d => d[realKey] <= filters[key],
36-
);
37-
return;
38-
}
39-
if (key.indexOf('_gte') !== -1) {
40-
// less than or equal
41-
const realKey = key.replace(/(_gte)$/, '');
42-
items = items.filter(
43-
d => d[realKey] >= filters[key],
44-
);
45-
return;
46-
}
47-
if (key.indexOf('_lt') !== -1) {
48-
// less than or equal
49-
const realKey = key.replace(/(_lt)$/, '');
50-
items = items.filter(
51-
d => d[realKey] < filters[key],
52-
);
53-
return;
54-
}
55-
if (key.indexOf('_gt') !== -1) {
56-
// less than or equal
57-
const realKey = key.replace(/(_gt)$/, '');
58-
items = items.filter(
59-
d => d[realKey] > filters[key],
60-
);
61-
return;
62-
}
63-
64-
items = items.filter(d => d[key] == filters[key]);
65-
});
66-
67-
if (filters.q) {
68-
items = items.filter(d =>
69-
Object.keys(d).some(key =>
70-
d[key].toString().includes(filters.q),
71-
),
72-
);
73-
}
74-
}
75-
76-
if (page !== undefined && perPage) {
77-
items = items.slice(
78-
page * perPage,
79-
page * perPage + perPage,
80-
);
81-
}
82-
83-
return {
84-
items,
85-
totalCount: entityData.length,
86-
};
87-
},
88-
[`get${entity}`]: (r, { id }) => entityData.find(d => d.id == id),
89-
};
90-
};
91-
92-
const mockMutationsForEntity = entity => {
93-
let entityData = currentData[pluralize(entity).toLowerCase()];
94-
95-
return {
96-
[`create${entity}`]: (root, { data }) => {
97-
const { __typename, ...parsedData } = JSON.parse(data);
98-
const newEntity = {
99-
id: entityData[entityData.length - 1].id + 1,
100-
...parsedData,
101-
};
102-
103-
entityData.push(newEntity);
104-
return newEntity;
105-
},
106-
[`update${entity}`]: (root, { data }) => {
107-
const { id, __typename, ...parsedData } = JSON.parse(data);
108-
const parsedId = parseInt(id, 10);
109-
const indexOfEntity = entityData.findIndex(
110-
e => e.id === parsedId,
111-
);
112-
113-
entityData[indexOfEntity] = { id: parsedId, ...parsedData };
114-
return parsedData;
115-
},
116-
[`remove${entity}`]: (root, { id }) => {
117-
entityData = entityData.filter(e => e.id !== id);
118-
},
119-
};
120-
};
121-
122-
const mocks = {
123-
Query: () => ({
124-
...mockQueriesForEntity('Customer'),
125-
...mockQueriesForEntity('Category'),
126-
...mockQueriesForEntity('Product'),
127-
...mockQueriesForEntity('Command'),
128-
...mockQueriesForEntity('Review'),
129-
}),
130-
Mutation: () => ({
131-
...mockMutationsForEntity('Customer'),
132-
...mockMutationsForEntity('Category'),
133-
...mockMutationsForEntity('Product'),
134-
...mockMutationsForEntity('Command'),
135-
...mockMutationsForEntity('Review'),
136-
}),
137-
};
138-
139-
addMockFunctionsToSchema({
140-
schema,
141-
mocks,
142-
});
143-
}
2+
export { default as graphQLClientServer } from './graphQLClientServer';
3+
export { default as jsonGraphqlExpress } from './jsonGraphqlExpress';

0 commit comments

Comments
 (0)