├── .babelrc ├── README.md ├── graphql └── Schema │ └── Schema.js ├── index.html ├── mongoose └── todo.js ├── package.json └── server.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015","stage-0"] 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Graph SQL Server Example 2 | 3 | This is a short example to help setup a GraphQL server on Node using Express and connect to Mongo DB using Mongoose. 4 | 5 | > Refer `package.json`'s ***dependencies*** and ***devDependencies*** to see the npm packages and versions used. 6 | 7 | ### Important Files and Folders 8 | 9 | |File/Folder|Description| 10 | |-----------|-----------| 11 | |**index.html**| The main HTML file| 12 | |**server.js**| GraphQL Express Server| 13 | |**graphql**| Folder related to graphQL Schema.| 14 | |**mongoose**| Folder related to Mongoose(mongodb) *Schema* and *Model*| 15 | 16 | ### Pre-requisites for this example to work. 17 | This example uses mongodb installed on the local machine. 18 | 19 | * Refer [Installation](https://docs.mongodb.com/manual/administration/install-community/) for instructions to install mongodb locally on your machine. 20 | * MongoDb has only a CLI, so you can install any UI tools for mongodb so that its easier to work on the database. I have installed [robomongo](https://robomongo.org/) and find it perfect for my basic use cases. 21 | 22 | ### Starting the GraphQL server 23 | * Before running the example we start the mongo db service using the below command. 24 | ``` 25 | sudo service mongod start 26 | ``` 27 | 28 | * Once the service is up and running, then issue the below command to start your graph QL server. 29 | ***Note*** - *babel-node is to be used in Dev environments only.* 30 | ``` 31 | npm run dev3 32 | ``` 33 | 34 | ### Testing the server 35 | * In this example we have a mongodb collection called ***TodoList*** which has the below schema: 36 | ``` 37 | itemId: Number, 38 | item: String, 39 | completed: Boolean 40 | 41 | ``` 42 | 43 | * Once the server is up, go to browser and run http://localhost:3000/. 44 | * The first section is a simple form which you can use to insert a new task to the ***TodoList*** collection. 45 | > As this is a basic example, only the property `item` is taken from the html, while `itemId` and `completed` are **hardcoded** as *1* and *false* respectively. 46 | * The second section is where we can see how GraphQL is used to GET value from ***TodoList*** where `itemId = 1`(hardcoded), by clicking on the link. 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /graphql/Schema/Schema.js: -------------------------------------------------------------------------------- 1 | import { 2 | GraphQLObjectType, 3 | GraphQLNonNull, 4 | GraphQLSchema, 5 | GraphQLString, 6 | GraphQLList, 7 | GraphQLInt, 8 | GraphQLBoolean 9 | } from 'graphql/type'; 10 | 11 | import ToDoMongo from '../../mongoose/todo' 12 | 13 | /** 14 | * generate projection object for mongoose 15 | * @param {Object} fieldASTs 16 | * @return {Project} 17 | */ 18 | export function getProjection (fieldASTs) { 19 | return fieldASTs.fieldNodes[0].selectionSet.selections.reduce((projections, selection) => { 20 | projections[selection.name.value] = true; 21 | return projections; 22 | }, {}); 23 | } 24 | 25 | var todoType = new GraphQLObjectType({ 26 | name: 'todo', 27 | description: 'todo item', 28 | fields: () => ({ 29 | itemId: { 30 | type: (GraphQLInt), 31 | description: 'The id of the todo.', 32 | }, 33 | item: { 34 | type: GraphQLString, 35 | description: 'The name of the todo.', 36 | }, 37 | completed: { 38 | type: GraphQLBoolean, 39 | description: 'Completed todo? ' 40 | } 41 | }) 42 | }); 43 | 44 | var schema = new GraphQLSchema({ 45 | query: new GraphQLObjectType({ 46 | name: 'RootQueryType', 47 | fields: { 48 | todo: { 49 | type: new GraphQLList(todoType), 50 | args: { 51 | itemId: { 52 | name: 'itemId', 53 | type: new GraphQLNonNull(GraphQLInt) 54 | } 55 | }, 56 | resolve: (root, {itemId}, source, fieldASTs) => { 57 | var projections = getProjection(fieldASTs); 58 | var foundItems = new Promise((resolve, reject) => { 59 | ToDoMongo.find({itemId}, projections,(err, todos) => { 60 | err ? reject(err) : resolve(todos) 61 | }) 62 | }) 63 | 64 | return foundItems 65 | } 66 | } 67 | } 68 | }) 69 | 70 | }); 71 | 72 | export default schema; 73 | 74 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GraphQL Express 6 | 7 | 8 |
9 |

Testing a simple GraphQL Server

10 |
11 |

This is just a normal POST

12 |
Enter a new item in the text box and hit Submit to save it to the database
13 |
14 | 15 | 16 |
17 |
18 |

GraphQL Test

19 |
20 |
21 | GraphQL Test 22 |
23 | 24 | -------------------------------------------------------------------------------- /mongoose/todo.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | 3 | var Schema = mongoose.Schema; 4 | 5 | // create a schema 6 | var toDoSchema = new Schema({ 7 | itemId: Number, 8 | item: String, 9 | completed: Boolean 10 | }, {collection:"TodoList"}); 11 | 12 | // the schema is useless so far 13 | // we need to create a model using it 14 | var ToDo = mongoose.model('ToDo', toDoSchema); 15 | 16 | export default ToDo 17 | 18 | // Select an item from TodoList collection 19 | // ToDo.find({item:"Gethyl"},(err,res)=>{ 20 | // if (err){console.log("---Gethyl not found in ToDo" + err)} 21 | // else console.log("+++Gethyl fetched ==> " + res) 22 | // }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo", 3 | "version": "1.0.0", 4 | "description": "Todo Express-MongoDB server", 5 | "main": "server.js", 6 | "scripts": { 7 | "dev": "nodemon server.js", 8 | "dev3": "babel-node server.js" 9 | 10 | }, 11 | "author": "Gethyl George", 12 | "license": "ISC", 13 | "dependencies": { 14 | "body-parser": "^1.15.2", 15 | "express": "^4.14.0", 16 | "express-graphql": "^0.6.1", 17 | "graphql": "^0.8.2", 18 | "mongoose": "^4.7.2" 19 | }, 20 | "devDependencies": { 21 | "babel": "^6.5.2", 22 | "babel-cli": "^6.18.0", 23 | "babel-preset-es2015": "^6.18.0", 24 | "babel-preset-stage-0": "^6.16.0", 25 | "nodemon": "^1.11.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import mongoose from 'mongoose'; 3 | import bodyParser from 'body-parser'; 4 | import ToDo from './mongoose/todo' 5 | import schema from './graphql/Schema/Schema' 6 | const app = express(); 7 | 8 | import {graphql} from 'graphql' 9 | import graphqlHTTP from 'express-graphql'; 10 | 11 | app.use(bodyParser.urlencoded({extended:true})) 12 | 13 | mongoose.connect('mongodb://localhost:27017/local') 14 | 15 | var db = mongoose.connection; 16 | db.on('error', ()=> {console.log( '---FAILED to connect to mongoose')}) 17 | db.once('open', () => { 18 | console.log( '+++Connected to mongoose') 19 | }) 20 | 21 | app.listen(3000,()=> {console.log("+++Express Server is Running!!!")}) 22 | 23 | app.get('/',(req,res)=>{ 24 | res.sendFile(__dirname + '/index.html') 25 | }) 26 | 27 | app.use('/graphql', graphqlHTTP (req => ({ 28 | schema 29 | //,graphiql:true 30 | }))) 31 | 32 | app.post('/quotes',(req,res)=>{ 33 | // Insert into TodoList Collection 34 | var todoItem = new ToDo({ 35 | itemId:1, 36 | item:req.body.item, 37 | completed: false 38 | }) 39 | 40 | todoItem.save((err,result)=> { 41 | if (err) {console.log("---TodoItem save failed " + err)} 42 | console.log("+++TodoItem saved successfully "+todoItem.item) 43 | 44 | res.redirect('/') 45 | }) 46 | }) 47 | --------------------------------------------------------------------------------