Skip to content
This repository was archived by the owner on Nov 5, 2024. It is now read-only.

Commit e1e5727

Browse files
xavxyzpauldowman
authored andcommitted
⊂(◕‿◕)つ ADVANCED GRAPHQL
1 parent 6a40b58 commit e1e5727

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+12892
-0
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# editorconfig.org
2+
root = true
3+
4+
[*]
5+
indent_style = space
6+
indent_size = 2
7+
end_of_line = lf
8+
charset = utf-8
9+
insert_final_newline = true

README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# OK GROW! Training
2+
3+
> If your computer is already set up, look at the `README` of the `/api` & `/ui` folders to get started!
4+
5+
## Computer Setup
6+
7+
Have a look at the software requirements and please install the missing ones.
8+
9+
### Versioning
10+
11+
We’ll use [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) to complete exercises.
12+
13+
### Code editor
14+
15+
We recommend [Atom](https://atom.io/) with the following packages installed:
16+
17+
* linter
18+
* linter-eslint
19+
* language-babel
20+
* autocomplete-modules
21+
* prettier
22+
23+
If you prefer to use another editor, please check for corresponding packages.
24+
25+
### Node.js
26+
27+
You’ll need Node.js installed. We recommend the use of [NVM](https://nvm.sh). You can also install it from the [official website](https://nodejs.org). We’ll use Node 8 (LTS).
28+
29+
Though Node comes with a package manager called npm, we’ll use [Yarn](https://yarnpkg.com), a modern deterministic packager (we’ll cover its benefits).
30+
31+
## Prerequisite knowledge
32+
33+
We will explore all of this thoroughly during the course, but if you are not comfortable with the following concepts, these links are worth a look.
34+
35+
### Must have - GraphQL culture
36+
37+
Some background on GraphQL: “[So what’s this GraphQL thing I keep hearing about?](https://medium.freecodecamp.com/so-whats-this-graphql-thing-i-keep-hearing-about-baf4d36c20cf)
38+
39+
We won’t cover GraphQL fundamentals, like the Schema Definition Language or how to send an operation from the client to the server.
40+
41+
We will be using Apollo for client and server GraphQL operations. If you are unfamiliar with these tools (you may be used to GraphQL in other languages or different client), you’ll find useful to have a look at the documentation of the [Apollo server tools](https://www.apollographql.com/docs/graphql-tools/) & the [React integration](https://www.apollographql.com/docs/react/).
42+
43+
### Must have - JavaScript basics
44+
45+
We won’t cover basic JS syntax. You should know at least how to write a function. If you don’t, please take this free course on [Codecademy](https://www.codecademy.com).
46+
47+
### Nice to have - ES2015+
48+
49+
Recent tools are making good use of the newest features in ES2015 and even ES2016 and ES2017. The newest JavaScript is a joy to use. If you haven't tried these, I hope you'll enjoy getting to know the new JS: http://es6-features.org/
50+
51+
Used in this class
52+
53+
* modules with import/export
54+
* const and let
55+
* arrow functions (also related: Function.bind(), which we'll see in React)
56+
* destructuring, rest and spread operators
57+
* template literals (everywhere, but a special use in GraphQL)
58+
* async/await - APIs and Apollo
59+
* Array.concat()
60+
61+
### Nice to have - React culture
62+
63+
We will be using [React](https://facebook.github.io/react/) to render client components.
64+
65+
One nice thing about React is that it is close to base JS, so you should be able to follow even if you are new to it. Nevertheless, some understanding of it will be highly useful. We will implement the GraphQL integration with higher-order components. We recommend that you read this post to understand the concept of container components, and then this post to understand generating container components using higher-order components.
66+
67+
If you want to go a little deeper and understand our perspective on higher-order-components, read [our blog post on the subject](https://www.okgrow.com/posts/compose-react-sphoc) and look at the [recompose](https://github.com/acdlite/recompose) library.
68+
69+
## Questions before the course starts
70+
71+
Depending on your current level, you can expect to spend up to several hours on this material. It's worth it, and you will get much more from the class. If anything here is confusing or you want to clarify a fine point, please get in touch. We are happy to answer your questions, before, during, and after the class.
72+
73+
Ping us on Twitter:
74+
75+
* Robert Dickert - [@rdickert](https://twitter.com/rdickert)
76+
* Paul Dowman - [@pauldowman](https://twitter.com/pauldowman)
77+
78+
Or email us at [training@okgrow.com](mailto:training@okgrow.com)
79+
80+
## Code Quality
81+
82+
We strive to use best practices in this repo, but we prioritize the learning experience where necessary.
83+
84+
This usually just means a simplified file structure, but this app lacks some safety and security features, so please use your judgment when reusing this code.
85+
86+
If you have any questions or concerns about specific code, please ask us; we love to talk about code quality.

api/.babelrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
presets: ['env'],
3+
plugins: [
4+
'transform-runtime',
5+
'transform-async-generator-functions',
6+
'transform-object-rest-spread',
7+
],
8+
}

api/.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
PORT=8080
2+
GOOGLE_API_KEY=
3+
DARKSKY_API_KEY=
4+
ENGINE_API_KEY=

api/.eslintrc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extends": ["prettier"],
3+
"plugins": ["prettier"],
4+
"rules": {
5+
"prettier/prettier": [
6+
"error",
7+
{
8+
"singleQuote": true,
9+
"trailingComma": "es5",
10+
"printWidth": 80
11+
}
12+
]
13+
}
14+
}

api/.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/db
2+
/node_modules
3+
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
8+
.env

api/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# OK GROW! Training - API Server
2+
3+
```sh
4+
# make a .env file from the example
5+
cp .env.example .env
6+
```
7+
8+
Update the .env file with your api keys:
9+
10+
* GOOGLE_API_KEY - use the same value as REACT_APP_GOOGLE_API_KEY in the ui folder: [Google Maps API](https://developers.google.com/maps/documentation/javascript/get-api-key)
11+
* [DARKSKY_API_KEY](https://darksky.net/dev)
12+
* [ENGINE_API_KEY](https://engine.apollographql.com/)
13+
14+
```sh
15+
# install the dependencies
16+
yarn
17+
18+
# run the API server
19+
yarn start
20+
```
21+
22+
If the API server doesn't start, you may need to start MongoDB in a separate terminal window (you will have to make sure [mongo is installed](https://docs.mongodb.com/manual/installation/)):
23+
24+
```sh
25+
# Usually not necessary
26+
mongod
27+
```

api/index.js

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import dotenv from 'dotenv-safe';
2+
import nodemon from 'nodemon';
3+
import fs from 'fs';
4+
import path from 'path';
5+
import mongoPrebuilt from 'mongodb-prebuilt';
6+
import denodeify from 'denodeify';
7+
8+
const dbpath = `${__dirname}/db`;
9+
10+
dotenv.config();
11+
12+
const {
13+
PORT = 8080,
14+
MONGO_PORT = parseInt(PORT, 10) + 2,
15+
MONGO_URL
16+
} = process.env;
17+
18+
// Taken from https://github.com/meteor/meteor/blob/debug-circle-timeout-promise-await/tools/utils/mongo-exit-codes.js
19+
const MONGO_CODES = {
20+
0: {
21+
code: 0,
22+
symbol: 'EXIT_CLEAN',
23+
longText: 'MongoDB exited cleanly'
24+
},
25+
1: {
26+
code: 1,
27+
// No symbol in the source. This is in src/mongo/base/initializer.cpp.
28+
symbol: 'global-initialization',
29+
longText: 'MongoDB failed global initialization'
30+
},
31+
2: {
32+
code: 2,
33+
symbol: 'EXIT_BADOPTIONS',
34+
longText:
35+
'MongoDB was started with erroneous or incompatible command line options'
36+
},
37+
3: {
38+
code: 3,
39+
symbol: 'EXIT_REPLICATION_ERROR',
40+
longText:
41+
'There was an inconsistency between hostnames specified\n' +
42+
'on the command line compared with hostnames stored in local.sources'
43+
},
44+
4: {
45+
code: 4,
46+
symbol: 'EXIT_NEED_UPGRADE',
47+
longText: 'MongoDB needs to upgrade to use this database'
48+
},
49+
5: {
50+
code: 5,
51+
symbol: 'EXIT_SHARDING_ERROR',
52+
longText: 'A moveChunk operation failed'
53+
},
54+
12: {
55+
code: 12,
56+
symbol: 'EXIT_KILL',
57+
longText: 'The MongoDB process was killed, on Windows'
58+
},
59+
14: {
60+
code: 14,
61+
symbol: 'EXIT_ABRUPT',
62+
longText: 'Unspecified unrecoverable error. Exit was not clean'
63+
},
64+
20: {
65+
code: 20,
66+
symbol: 'EXIT_NTSERVICE_ERROR',
67+
longText: 'Error managing NT Service on Windows'
68+
},
69+
45: {
70+
code: 45,
71+
symbol: 'EXIT_FS',
72+
longText: 'MongoDB cannot open or obtain a lock on a file'
73+
},
74+
47: {
75+
code: 47,
76+
symbol: 'EXIT_CLOCK_SKEW',
77+
longText: 'MongoDB exited due to excess clock skew'
78+
},
79+
48: {
80+
code: 48,
81+
symbol: 'EXIT_NET_ERROR',
82+
longText:
83+
'MongoDB exited because its port was closed, or was already\n' +
84+
'taken by a previous instance of MongoDB'
85+
},
86+
100: {
87+
code: 100,
88+
symbol: 'EXIT_UNCAUGHT',
89+
longText:
90+
'MongoDB had an unspecified uncaught exception.\n' +
91+
'This can be caused by MongoDB being unable to write to a local database.\n' +
92+
`Check that you have permissions to write to ${dbpath}. MongoDB does\n` +
93+
'not support filesystems like NFS that do not allow file locking.'
94+
}
95+
};
96+
97+
if (!MONGO_URL) {
98+
console.log(
99+
`Creating development MongoDB on mongodb://localhost:${MONGO_PORT}`
100+
);
101+
102+
if (!fs.existsSync(dbpath)) {
103+
fs.mkdirSync(dbpath);
104+
}
105+
106+
// Weirdly, this promise never resolves if Mongo starts.
107+
// However, we'll just go ahead and start the node server anyway,
108+
// and if we see an error, we'll quit
109+
denodeify(mongoPrebuilt.start_server.bind(mongoPrebuilt))({
110+
auto_shutdown: true,
111+
args: {
112+
port: MONGO_PORT,
113+
dbpath
114+
}
115+
}).catch(errorCode => {
116+
const error = MONGO_CODES[errorCode];
117+
console.error(`Failed to start MongoDB server on port ${MONGO_PORT}`);
118+
console.error(
119+
`Error Code ${errorCode}: ${error ? error.longText : 'Unknown'}`
120+
);
121+
process.exit(1);
122+
});
123+
}
124+
125+
nodemon({
126+
script: path.join('src/server', 'index.js'),
127+
ext: 'js graphql',
128+
exec: 'babel-node'
129+
}).on('restart', () => console.log('Restarting server due to file change\n'));
130+
131+
// Ensure stopping our parent process will properly kill nodemon's process
132+
// Ala https://www.exratione.com/2013/05/die-child-process-die/
133+
134+
// SIGTERM AND SIGINT will trigger the exit event.
135+
process.once('SIGTERM', function() {
136+
process.exit(0);
137+
});
138+
process.once('SIGINT', function() {
139+
process.exit(0);
140+
});
141+
// And the exit event shuts down the child.
142+
process.once('exit', function() {
143+
nodemon.emit('SIGINT');
144+
});

api/package.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "training-api",
3+
"version": "0.1.0",
4+
"description": "",
5+
"scripts": {
6+
"start": "babel-node index.js"
7+
},
8+
"author": "OK GROW! (Xavier Cazalot @xav_cz & Robert Dickert @rdickert)",
9+
"devDependencies": {
10+
"babel-cli": "^6.24.0",
11+
"babel-eslint": "^7.2.3",
12+
"babel-plugin-transform-async-generator-functions": "^6.24.1",
13+
"babel-plugin-transform-object-rest-spread": "^6.23.0",
14+
"babel-plugin-transform-runtime": "^6.23.0",
15+
"babel-preset-env": "^1.6.0",
16+
"denodeify": "^1.2.1",
17+
"eslint": "^4.6.1",
18+
"eslint-config-prettier": "^2.4.0",
19+
"mongodb-prebuilt": "5.0.7",
20+
"nodemon": "^1.11.0",
21+
"prettier": "^1.7.0"
22+
},
23+
"dependencies": {
24+
"apollo-engine": "^0.8.1",
25+
"apollo-link": "^0.7.0",
26+
"apollo-link-http": "^0.7.0",
27+
"apollo-server-express": "^1.1.0",
28+
"body-parser": "^1.17.1",
29+
"cors": "^2.8.4",
30+
"dataloader": "^1.3.0",
31+
"dotenv-safe": "^4.0.4",
32+
"express": "^4.15.2",
33+
"graphql": "^0.11.7",
34+
"graphql-subscriptions": "^0.5.1",
35+
"graphql-tools": "^2.2.1",
36+
"jwt-simple": "^0.5.1",
37+
"lodash.merge": "^4.6.0",
38+
"mongodb": "^2.2.31",
39+
"node-fetch": "^1.7.3",
40+
"node-geocoder": "^3.20.0",
41+
"nodeify": "^1.0.1",
42+
"passport": "^0.3.2",
43+
"passport-jwt": "^2.2.1",
44+
"subscriptions-transport-ws": "^0.9.0"
45+
}
46+
}

api/src/model/Location.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import NodeGeocoder from 'node-geocoder';
2+
3+
const { GOOGLE_API_KEY } = process.env;
4+
5+
const geocoder = NodeGeocoder({
6+
provider: 'google',
7+
apiKey: GOOGLE_API_KEY,
8+
});
9+
10+
// basic loader making network request & returning a Promise
11+
const loader = {
12+
load: name => geocoder.geocode(name),
13+
};
14+
15+
export default class Location {
16+
async get(name) {
17+
if (!name) {
18+
return;
19+
}
20+
21+
try {
22+
const [location] = await loader.load(name);
23+
24+
return {
25+
...location,
26+
id: `${location.latitude}:${location.longitude}`,
27+
};
28+
} catch (e) {
29+
throw new Error(e);
30+
}
31+
}
32+
}

0 commit comments

Comments
 (0)