Automatically generates a GraphQL Server from mongoose models. Provides all the basic CRUD operations for all models on both native mongoose connection as well as created connections. Supports deep nested populations for queries.
Uses graphql-compose-mongooose and Apollo Server under the hood.
Install with npm
$ npm i mongoose-graphql-server --save
Install with yarn
$ yarn add mongoose-graphql-server
Use the endpoint /graphql
to open graphQL studio. The examples to implement can also be found here at examples repository
const mongoose = require('mongoose');
const {
generateSchema,
createGraphQLServer,
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
const Cat = mongoose.model('Cat', { name: String });
// Build the schema
const schema = generateSchema(mongoose);
// Create the graphQL server
const app = await createGraphQLServer(schema);
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open',init);
This package supports deep nested populations if using model names as refs or defining virtual fields on the models.
Define the first User
model in user.model.js
file
const {model, Schema, Types} = require('mongoose');
const userSchema = new Schema(
{
name: {
type: String,
},
username: {
type: String,
required: true,
indexed: true
},
isActive: {
type: Boolean,
default: true,
}
,
posts:[{
type: Types.ObjectId,
ref: "post",
}]
},
{
timestamps: true,
toObject: {
virtuals: true,
},
toJSON: {
virtuals: true,
},
}
);
const userModel = model('user', userSchema);
module.exports = userModel;
Define the second Post
model in post.model.js
file
const {model, Schema,Types} = require('mongoose');
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
description: {
type: String,
},
status: {
type: String,
enum: ['CREATED', 'DRAFT', 'PUBLISHED'],
required: true,
},
creator: {
type: Types.ObjectId,
ref:"user"
},
},
{
timestamps: true,
toObject: {
virtuals: true,
},
toJSON: {
virtuals: true,
},
}
);
const postModel = model('post', postSchema);
module.exports = postModel;
Create the server file index.js
const mongoose = require('mongoose');
const {
generateSchema,
createGraphQLServer,
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test1');
const db = mongoose.connection;
const init = async () => {
// Register models
require('./user.model.js');
require('./post.model.js');
// Build the schema
const schema = generateSchema(mongoose);
// Create the graphQL server
const app = await createGraphQLServer(schema);
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open',init);
Run the server
$ node index.js
Define the first User
model in user.model.js
file
const {model, Schema} = require('mongoose');
const userSchema = new Schema(
{
name: {
type: String,
},
isActive: {
type: Boolean,
default: true,
},
},
{
timestamps: true,
toObject: {
virtuals: true,
},
toJSON: {
virtuals: true,
},
}
);
userSchema.virtual('posts', {
ref: 'post',
foreignField: 'author_id',
localField: '_id',
});
const userModel = model('user', userSchema);
module.exports = userModel;
Define the second Post
model in post.model.js
file
const {model, Schema} = require('mongoose');
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
description: {
type: String,
},
status: {
type: String,
enum: ['CREATED', 'DRAFT', 'PUBLISHED'],
required: true,
},
author_id: {
type: String,
required: true,
},
},
{
timestamps: true,
toObject: {
virtuals: true,
},
toJSON: {
virtuals: true,
},
}
);
postSchema.virtual('author', {
ref: 'user',
foreignField: '_id',
localField: 'author_id',
justOne: true,
});
const postModel = model('post', postSchema);
module.exports = postModel;
Create the server file index.js
const mongoose = require('mongoose');
const {
generateSchema,
createGraphQLServer,
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
require('./user.model.js');
require('./post.model.js');
// Build the schema
const schema = generateSchema(mongoose);
// Create the graphQL server
const app = await createGraphQLServer(schema);
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open',init);
Run the server
$ node index.js
This package uses express as the default server to serve the graphQl endpoint, the createGraphQLServer
method returns an Express app instance. Further the server can be used as an express app middleware by using createGraphQLMiddleware
.
const mongoose = require('mongoose');
const express = require('express');
const {
generateSchema,
createGraphQLMiddleware
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
const Cat = mongoose.model('Cat', { name: String });
// Build the schema
const schema = generateSchema(mongoose);
let app = express();
const middleware = await createGraphQLMiddleware(schema);
app.use("/", middleware);
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open', init);
const mongoose = require('mongoose');
const {
generateSchema,
createGraphQLServer,
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
const Cat = mongoose.model('Cat', { name: String });
// Build the schema
const schema = generateSchema(mongoose);
// Create the graphQL server
const app = await createGraphQLServer(schema);
app.get("/",(req,res) => {
res.send("hello");
})
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open',init);
Run the server
$ node index.js
const mongoose = require('mongoose');
const express = require('express');
const {
generateSchema,
createGraphQLServer,
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
const Cat = mongoose.model('Cat', { name: String });
// Build the schema
const schema = generateSchema(mongoose);
let app = express();
app.get("/", (req, res) => {
res.send(`GrahpQL running on http://localhost:${PORT}/graphql`);
})
// Create the graphQL server
app = await createGraphQLServer(schema, app);
app.get("/test", (req, res) => {
res.send("ok")
})
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open', init);
Run the server
$ node index.js
When needed custom Query and Mutation fields can be defined in the GraphQl schema by using addQueryFields
and addMutationFields
functions. Additional types can also be defined using the schemaComposer
which is an instance of SchemaComposer from graqhql-compose. Full documentation for customization can be found on their official docs page.
const mongoose = require('mongoose');
const {
generateSchema,
createGraphQLServer,
addQueryFields,
addMutationFields,
schemaComposer
} = require('mongoose-graphql-server');
const PORT = process.env.port || 3000;
mongoose.connect('mongodb://localhost/test');
const db = mongoose.connection;
const init = async () => {
// Register models
const Cat = mongoose.model('Cat', { name: String });
// Build the schema
let schema = generateSchema(mongoose);
// Add custom types and input types
const Test = schemaComposer.createObjectTC(`
type Test {
name: String
age: Int
}
`);
const TestInput = schemaComposer.createInputTC(`
input TestInput {
name: String
}`);
// Add custom query fields
addQueryFields({
"testQuery": {
type: [Test],
args: { input: TestInput },
resolve: (source, args, context, info) => {
return [{ "name": "test", "age": 1 }];
},
}
})
// Add custom mutation fields
addMutationFields({
"testMutation": {
type: [Test],
args: { input: TestInput },
resolve: (source, args, context, info) => {
return [{ "name": "test", "age": 1 }];
},
}
})
//rebuild the schema
schema = schemaComposer.buildSchema();
// Create the graphQL server
const app = await createGraphQLServer(schema);
// Start the server
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}/`);
console.log(`GraphQL is running at http://localhost:${PORT}/graphql`);
})
}
db.once('open', init);
Features like schema introspection, cache, csrfPrevention can be configured by passing in the Apollo Server Configuration Object in the createGraphQLServer
method.
const app = await createGraphQLServer({
schema,
introspection: false
});
The full list of customization options can be found at Apollo Server Docs
- At the moment populations are supported only on virtual fields and model names.
- Supports sort and filter only on indexed fields at the moment.
- Populating key needs to be present for deep nested populations of virtual fields.
- Write the documentation
- Write Tests
- Fix issues
- Support custom field generator on genrated schema
- Addition of custom query and mutation resolvers
- Converting this project to typescript