├── .gitignore ├── Procfile ├── package.json ├── schema.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: npm start 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todo-mongo-graphql-server", 3 | "version": "1.0.0", 4 | "description": "GraphQL server for Todo List", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node server.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/igorlima/todo-mongo-graphql-server.git" 13 | }, 14 | "keywords": [ 15 | "GraphQL" 16 | ], 17 | "author": "igorlima", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/igorlima/todo-mongo-graphql-server/issues" 21 | }, 22 | "homepage": "https://github.com/igorlima/todo-mongo-graphql-server#readme", 23 | "dependencies": { 24 | "express": "^4.13.3", 25 | "express-graphql": "^0.4.4", 26 | "graphql": "^0.4.12", 27 | "mongoose": "^4.2.5" 28 | }, 29 | "standard": { 30 | "ignore": [ 31 | "Procfile" 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /schema.js: -------------------------------------------------------------------------------- 1 | var mongoose = require('mongoose') 2 | var Schema = mongoose.Schema 3 | var graphql = require('graphql') 4 | var GraphQLObjectType = graphql.GraphQLObjectType 5 | var GraphQLBoolean = graphql.GraphQLBoolean 6 | var GraphQLID = graphql.GraphQLID 7 | var GraphQLString = graphql.GraphQLString 8 | var GraphQLList = graphql.GraphQLList 9 | var GraphQLNonNull = graphql.GraphQLNonNull 10 | var GraphQLSchema = graphql.GraphQLSchema 11 | 12 | // Mongoose Schema definition 13 | var TODO = mongoose.model('Todo', new Schema({ 14 | id: mongoose.Schema.Types.ObjectId, 15 | title: String, 16 | completed: Boolean 17 | })) 18 | 19 | /* 20 | * I’m sharing my credentials here. 21 | * Feel free to use it while you’re learning. 22 | * After that, create and use your own credential. 23 | * Thanks. 24 | * 25 | * to connect to a local instance of MongoDB use 26 | * COMPOSE_URI=mongodb://example:example@127.0.0.1:27017/todo 27 | */ 28 | var COMPOSE_URI_DEFAULT = 'mongodb://graphqltodosuser:graphqltodospassword@candidate.12.mongolayer.com:11219,candidate.60.mongolayer.com:10594/graphqltodos?replicaSet=set-569540e711469f811f0000a2' 29 | mongoose.connect(process.env.COMPOSE_URI || COMPOSE_URI_DEFAULT, function (error) { 30 | if (error) console.error(error) 31 | else console.log('mongo connected') 32 | }) 33 | /** END */ 34 | 35 | var TodoType = new GraphQLObjectType({ 36 | name: 'todo', 37 | fields: () => ({ 38 | id: { 39 | type: GraphQLID, 40 | description: 'Todo id' 41 | }, 42 | title: { 43 | type: GraphQLString, 44 | description: 'Task title' 45 | }, 46 | completed: { 47 | type: GraphQLBoolean, 48 | description: 'Flag to mark if the task is completed' 49 | } 50 | }) 51 | }) 52 | 53 | var promiseListAll = () => { 54 | return new Promise((resolve, reject) => { 55 | TODO.find((err, todos) => { 56 | if (err) reject(err) 57 | else resolve(todos) 58 | }) 59 | }) 60 | } 61 | 62 | var QueryType = new GraphQLObjectType({ 63 | name: 'Query', 64 | fields: () => ({ 65 | todos: { 66 | type: new GraphQLList(TodoType), 67 | resolve: () => { 68 | return promiseListAll() 69 | } 70 | } 71 | }) 72 | }) 73 | 74 | var MutationAdd = { 75 | type: TodoType, 76 | description: 'Add a Todo', 77 | args: { 78 | title: { 79 | name: 'Todo title', 80 | type: new GraphQLNonNull(GraphQLString) 81 | } 82 | }, 83 | resolve: (root, args) => { 84 | var newTodo = new TODO({ 85 | title: args.title, 86 | completed: false 87 | }) 88 | newTodo.id = newTodo._id 89 | return new Promise((resolve, reject) => { 90 | newTodo.save(function (err) { 91 | if (err) reject(err) 92 | else resolve(newTodo) 93 | }) 94 | }) 95 | } 96 | } 97 | 98 | var MutationToggle = { 99 | type: TodoType, 100 | description: 'Toggle the todo', 101 | args: { 102 | id: { 103 | name: 'Todo Id', 104 | type: new GraphQLNonNull(GraphQLString) 105 | } 106 | }, 107 | resolve: (root, args) => { 108 | return new Promise((resolve, reject) => { 109 | TODO.findById(args.id, (err, todo) => { 110 | if (err) { 111 | reject(err) 112 | return 113 | } 114 | 115 | if (!todo) { 116 | reject('Todo NOT found') 117 | return 118 | } else { 119 | todo.completed = !todo.completed 120 | todo.save((err) => { 121 | if (err) reject(err) 122 | else resolve(todo) 123 | }) 124 | } 125 | }) 126 | }) 127 | } 128 | } 129 | 130 | var MutationDestroy = { 131 | type: TodoType, 132 | description: 'Destroy the todo', 133 | args: { 134 | id: { 135 | name: 'Todo Id', 136 | type: new GraphQLNonNull(GraphQLString) 137 | } 138 | }, 139 | resolve: (root, args) => { 140 | return new Promise((resolve, reject) => { 141 | TODO.findById(args.id, (err, todo) => { 142 | if (err) { 143 | reject(err) 144 | } else if (!todo) { 145 | reject('Todo NOT found') 146 | } else { 147 | todo.remove((err) => { 148 | if (err) reject(err) 149 | else resolve(todo) 150 | }) 151 | } 152 | }) 153 | }) 154 | } 155 | } 156 | 157 | var MutationToggleAll = { 158 | type: new GraphQLList(TodoType), 159 | description: 'Toggle all todos', 160 | args: { 161 | checked: { 162 | name: 'Todo Id', 163 | type: new GraphQLNonNull(GraphQLBoolean) 164 | } 165 | }, 166 | resolve: (root, args) => { 167 | return new Promise((resolve, reject) => { 168 | TODO.find((err, todos) => { 169 | if (err) { 170 | reject(err) 171 | return 172 | } 173 | TODO.update({ 174 | _id: { 175 | $in: todos.map((todo) => todo._id) 176 | } 177 | }, { 178 | completed: args.checked 179 | }, { 180 | multi: true 181 | }, (err) => { 182 | if (err) reject(err) 183 | else promiseListAll().then(resolve, reject) 184 | }) 185 | }) 186 | }) 187 | } 188 | } 189 | 190 | var MutationClearCompleted = { 191 | type: new GraphQLList(TodoType), 192 | description: 'Clear completed', 193 | resolve: () => { 194 | return new Promise((resolve, reject) => { 195 | TODO.find({completed: true}, (err, todos) => { 196 | if (err) { 197 | reject(err) 198 | } else { 199 | TODO.remove({ 200 | _id: { 201 | $in: todos.map((todo) => todo._id) 202 | } 203 | }, (err) => { 204 | if (err) reject(err) 205 | else resolve(todos) 206 | }) 207 | } 208 | }) 209 | }) 210 | } 211 | } 212 | 213 | var MutationSave = { 214 | type: TodoType, 215 | description: 'Edit a todo', 216 | args: { 217 | id: { 218 | name: 'Todo Id', 219 | type: new GraphQLNonNull(GraphQLString) 220 | }, 221 | title: { 222 | name: 'Todo title', 223 | type: new GraphQLNonNull(GraphQLString) 224 | } 225 | }, 226 | resolve: (root, args) => { 227 | return new Promise((resolve, reject) => { 228 | TODO.findById(args.id, (err, todo) => { 229 | if (err) { 230 | reject(err) 231 | return 232 | } 233 | 234 | if (!todo) { 235 | reject('Todo NOT found') 236 | return 237 | } 238 | 239 | todo.title = args.title 240 | todo.save((err) => { 241 | if (err) reject(err) 242 | else resolve(todo) 243 | }) 244 | }) 245 | }) 246 | } 247 | } 248 | 249 | var MutationType = new GraphQLObjectType({ 250 | name: 'Mutation', 251 | fields: { 252 | add: MutationAdd, 253 | toggle: MutationToggle, 254 | toggleAll: MutationToggleAll, 255 | destroy: MutationDestroy, 256 | clearCompleted: MutationClearCompleted, 257 | save: MutationSave 258 | } 259 | }) 260 | 261 | module.exports = new GraphQLSchema({ 262 | query: QueryType, 263 | mutation: MutationType 264 | }) 265 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express') 2 | var Schema = require('./schema') 3 | var graphQLHTTP = require('express-graphql') 4 | 5 | var app = express() 6 | app.use('/', graphQLHTTP({ 7 | schema: Schema, 8 | pretty: true, 9 | graphiql: true 10 | })) 11 | app.listen(process.env.PORT || 8080, (err) => { 12 | if (err) { 13 | console.error(err) 14 | return 15 | } 16 | console.log(`GraphQL Server is now running on localhost:${process.env.PORT || 8080}`) 17 | }) 18 | --------------------------------------------------------------------------------