GraphQL server with Express JS and mongodb
GraphQL developed by Facebook in 2012 and publicly available in 2015. GraphQL is alternative of REST full web service. It allows clients Query with flexible data structure which are required for client. It also support the data manipulation and modification functionlaity named mutation
Like rest api. GraphQL provide official middleware for express server named express-graphql
.
Over the past two month, I tried to learn about graphql
and graphql
connection with database
using express js
. I read some blogs and article. Most of the author provide the example or tutorial which graphql
is related to static
json data. Some blog are provide simple example with one graphql's
type
.
So I am tried to read those blogs and graphql
documentation again and again. Last tow week ago, I think about some idea about how i connect the mongodb
with graphql
using express js
as web server. create the example which provides CRUD operation functionality with tow mongodb
collections
with one to many
relation. this project will provide the idea about how developer handle the one to many
and many to many
relation graphql's
type
using mongoose
and graphql-express
.This Project will also show the path how to build better web service structure using graphql with express js.
Installation instructions
- clone the repository
git clone https://github.com/tariqulislam/express-graphql-basic-server.git
- For Yarn run command
yarn install
- Or for npm run command
npm install
Prerequsite and configurations
- Install the
mongodb
andStudio 3T
non commercial version. - Create Database to mongodb named
graphqltest
- Add username and password to mongodb and provide all permission to database.
- Grant all permission to user.
- Import
json
file fromdb
folder tographqltest
database. - Change the
.env
file for database configuration
DATABASE_HOST=localhost
DATABASE_PORT=27017
DATABASE_USER=<username>
DATABASE_PASS=<password>
DATABASE_NAME=graphqltest
7. run the application by commandline using yarn start
or npm start
Project Structure
EXPORESS-GRAPHQL-WITH-MONGOOSE
|--| config (file for graphql and express and mongoose)
|----| database.js (database configuration file)
|--| db (mongodb exported collection)
|----| <mongodb collection>.json (mongodb exported file)
|--| src (Project soruce file directory)
|----| graphql (All graphql related file directory)
|------| mutations (All graphql mutation related file directory)
|--------| <Type Wise Mutation>.js (Graphql type wise mutation)
|--------| index.js(export all mutation to other module)
|------| queries (All GraphQL Query related files)
|--------| <GraphQL type file>.js (Individual Graphql type)
|--------| index.js (GraphQL Root Type file)
|----| models (All mongoose ODM related file)
|------| <mongoose model>.js (mongoose model and schema)
|----| schema.js (GraphQL Schema building file)
|--| .env (node js environment variable related file)
|--| index.js (web server and mongoose and GraphQL Endpoint)
Introductions and knowladgebase
- GraphQL
- express JS
- dotenv
- mongoose
- Graphqli
- nodemon
What is GraphQL?
GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools!alt text.
What is graphql-express?
GraphQL HTTP server with any HTTP web framework that supports connect styled middleware, including Connect itself, Express and Restify.
What is mongoose?
Mongoose is an object data modeling (ODM) library that provides a rigorous modeling environment for your data, enforcing structure as needed while still maintaining the flexibility that makes MongoDB powerful.
Express JS
Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.
Sample coding for create graphql api for client
Create the mongoose schema for database interactions
- Go to
src/models
folder - Create file
Author.js
andPost.js
// src/models/Author.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const authorSchema = new Schema({
name: { type: String },
email: {type: String, required: true, unique: true}
});
const Author = mongoose.model('Author', authorSchema);
module.exports = Author;// src/models/Post.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const postSchema = new Schema({
author_id: Schema.Types.ObjectId,
title: String,
category: String,
body: String
});
const Post = mongoose.model('Post', postSchema);
module.exports = Post;
this code snappit contains the model
defination for mongodb
using mongoose
ODM.
- First I add
mongoose
by addingjavascript const mongoose = require('mongoose');
- Then add the
javascript const Schema = mongoose.Schema;
schema for support different datatype and constraint ofmongoose
- Schema defination for
authorSchema
andpostSchema
contains themongodb
collection
information
What is Schema in Graphql?
GraphQL has its own type language that’s used the write GraphQL schemas: The Schema Definition Language (SDL). Schema contains the some attributes named.!GraphQL Documentation
- Query
- Mutation
- Subscription
What is Type in graphql?
The most basic components of a GraphQL schema are object types, which just represent a kind of object you can fetch from your service, and what fields it has. In the GraphQL schema language, we might represent it like this!GraphQL Documentation:
type PostType {
id: ID!
title: String!
body: String!
author: [AuthorType]!
}
AuthorType
: is a Graphql Object Typeid
,title
andbody
,AuthorType
is field name of Object TypeString
andID
isDataType
of thefield
. this type is called asScalarType
and- After
DataType
!
symbol meansnon-nullable
[AuthorType]!
meansarray
ofAuthorType
object which is embedded withAuthorType
Object Type
How to Create Type of ObjectType in GraphQL?
const { GraphQLString, GraphQLObjectType, GraphQLNonNull } = require('graphql');
const AuthorType = new GraphQLObjectType({
name: 'AuthorType',
description: "This represent an author",
fields: () => ({
_id: {type: new GraphQLNonNull(GraphQLString)},
name: {type: new GraphQLNonNull(GraphQLString)},
email: {type: GraphQLString}
})
});module.exports = AuthorType;
express-graphql
provide theGraphQLObjectType
which is provide all functionality of graphqlType
andQuery
.- I define
AuthorType
as aGraphQLObjectType
atsrc/graphql/querie/AuthorType.js
// src/graphql/querie/AuthorType.jsconst { GraphQLString, GraphQLObjectType, GraphQLNonNull } = require('graphql');
const Author = require('../../models/Author');
const AuthorType = require('./AuthorType');
const mongoose = require('mongoose');
const PostType = new GraphQLObjectType({
name: 'PostType',
description: "This is resent post",
fields: () => ({
_id: {type: new GraphQLNonNull(GraphQLString)},
title: {type: GraphQLString},
body: {type: GraphQLString},
author_id: {type: GraphQLString},
author: {type: AuthorType, resolve: async function (post) {
var authors = await Author.findById(
mongoose.Types.ObjectId(post.author_id))
if(!authors) {
throw new Error('Error')
}
return authors
}}
})
});module.exports = PostType
3. Define PostType
variable at src/graphql/queries/PostType.js
file, which contains the GraphQLObjectType
.
4. GraphQLObjectType
Object
which contains:
{
name: `<Name of the GrapQLObjectType or Graphql Type>`,
description: `<Description of the GraphQLObjectType`>,
fields: () => `(function which contains return the fields of the GraphQLObjectType)`{
type: `<Datatype of the Fields>`
resolve: `(function for resolve the field from api or database or from ORM or ODM)`
}
}
5. At PostType
graphql object type, I add author
field, the field contains resolver
async
function named resolve
used for finding Author
informtion from mongodb database using mongoose
.
6.var authors = await Author.findById(mongoose.Types.ObjectId(post.author_id))
return author
information related to specific post
7. To handle the error, throwing Error
object, by throw new Error('Error')
Or return authors,
which contains AuthorType
graphql Type with data.
What is Root Type in GraphQL?
At the top level of every GraphQL server is a type that represents all of the possible entry points into the GraphQL API, it’s often called the Root type or the Query type.!GraphQL Documentation
How to Create Root Type for Schema by express-graphql?
In this project I have create the root type at file src/graphql/queries/index.js
// src/graphql/queries/index.jsconst { GraphQLList, GraphQLObjectType } = require('graphql');
const Author = require('../../models/Author')
const Post = require('../../models/Post')
const PostType = require('./PostType');
const AuthorType = require('./AuthorType')const BlogQueryRootType = new GraphQLObjectType ({
name: 'BlogAppSchema',
description: "Blog Application Schema Query Root",
fields: () => ({
authors: {
type: new GraphQLList(AuthorType),
description: "List of all Authors",
resolve: async function () {
return await Author.find({}, (err, auth) => {
});
}
},
posts: {
type: new GraphQLList(PostType),
description: "List of all posts",
resolve: async function () {
var posts = await Post.find({})
return posts;
}
}
})
});module.exports = BlogQueryRootType
BlogQueryRootType
is a root type and also aGraphQLObjectType
which contains all the attribute and functions like otherGraphQLObjectType
.- In
fileds
is functions which contains all theQuery
of the Schema. For Every GraphQLfield
has its ownresolve
options. authors
andposts
fieldsresolve
list of a thoseGraphQLObjectType
.
What is Mutations in GraphQL?
In REST, any request might end up causing some side-effects on the server, but by convention it’s suggested that one doesn’t use GET requests to modify data. GraphQL is similar — technically any query could be implemented to cause a data write. However, it’s useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.
Just like in queries, if the mutation field returns an object type, you can ask for nested fields. This can be useful for fetching the new state of an object after an update.!GraphQL Documentation
How to Create Mutation by express-graphql?
- In this project I have create the directory
src/graphql/mutations
. - Then I have create the file named
AuthorMutation.js
andPostMutation.js
fileimport
the graphql express functions and library andimport
mongoose
models for mutation operations.
// src/graphql/mutations/AuthorMutation.js
var {GraphQLNonNull, GraphQLString} = require('graphql');
var AuthorType = require('../queries/AuthorType');
var Author = require('../../models/Author')
3. At AuthorMutations.js
file have added the three functions for mutations.
// src/graphql/mutations/AuthorMutation.js
const addAuthor = {
type: AuthorType,
args: {
name: {
name: 'name',
type: new GraphQLNonNull(GraphQLString)
},
email: {
name: 'email',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: async function (root, params) {
const uModel = new Author(params);
const newAuthor = await uModel.save();
if(!newAuthor) {
throw new Error('Error')
}
return newAuthor
}
}
4. For addAuthor
mutation contains one attributes
and one resolver
function
5. type
attribute is a GraphQLObjectType
. I have added AuthorType
graphql Object type for addAuthor
mutation.
6. args
attribute contains parameter for mutation. which are:
<argument_name>: {
name: <argument_name> // Optional,
type: <GraphQL_type> // `GraphQLNonNull` for checking the null value
}
7. resolve
function using for resolve the mutations. which contains the all the functionality to change or effect the models
or data
. I have use mongoose
save
function to save the new author to mongodb database. also use async
function to handle the mongodb operations.
8. Mutation for update the author information, i write the code to AuthorMutation.js
file. the function is updateAuthor
. which contains similar attribute like addAuthor
:
// src/graphql/mutations/AuthorMutation.js
const updateAuthor = {
type: AuthorType,
args: {
_id: {
name: '_id',
type: new GraphQLNonNull(GraphQLString)
},
name: {
name: 'name',
type: GraphQLString
},
email: {
name: 'email',
type: GraphQLString
}
},
resolve: async function(root, param) {
let updateAuthor = {};
if(param.name) {
updateAuthor.name = param.name
}
if(param.email) {
updateAuthor.email = param.email
}
const uAuthor = await Author.findByIdAndUpdate(param._id, updateAuthor, {new: true})
console.log(uAuthor)
if(!uAuthor) {
throw new Error('Error')
}
return uAuthor
}
}
9. For Delete author mutation structure is as like asaddAuthor
. the code snippet are shows below:
// src/graphql/mutations/AuthorMutation.js
const deleteAuthor = {
type: AuthorType,
args: {
_id: {
name: '_id',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: async function (root, param) {
const deleteAuthor = await Author.findByIdAndRemove(param._id)
if(!deleteAuthor) {
throw new Error('Error');
}
return deleteAuthor
}
}
10. Then export
those functions at the end of AuthorMutation.js
file:
// src/graphql/mutations/AuthorMutation.js
module.exports = {addAuthor, updateAuthor, deleteAuthor}
11. Similar way i have created PostMutation.js
file to provide mutation
functionality for PostType
:
// src/graphql/mutations/PostMutation.jsvar {GraphQLNonNull, GraphQLString} = require('graphql')
var Post = require('../../models/Post');
var PostType = require('../queries/PostType');const createPost = {
type: PostType,
args: {
title: {
name: "title",
type: new GraphQLNonNull(GraphQLString)
},
author_id: {
name: "author_id",
type: new GraphQLNonNull(GraphQLString)
},
body: {
name: "body",
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: async function(root, param) {
const postModel = new Post(param);
const savePost = await postModel.save();
if(!savePost) {
throw new Error('Error')
}
return savePost;
}
}const updatePost = {
type: PostType,
args: {
_id: {
name: "_id",
type: new GraphQLNonNull(GraphQLString)
},
author_id: {
name: "author_id",
type: GraphQLString
},
title: {
name: "title",
type: GraphQLString
},
body: {
name: "body",
type: GraphQLString
}
},
resolve: async function (root, param) {
let updatePost = {};
if(param.author_id) {
updatePost.author_id = param.author_id;
} if(param.title) {
updatePost.title = param.title
} if(param.body) {
updatePost.body = param.body
} const updatePostInfo = await Post.findByIdAndUpdate(param._id,updatePost,{new: true}); if(!updatePostInfo) {
throw new Error('Error');
}
return updatePostInfo;
}
}const deletePost = {
type: PostType,
args: {
_id: {
name: "_id",
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: async function (root, param) {
const deletePost = await Post.findByIdAndRemove(param._id);
if(deletePost) {
throw new Error('Error');
}
return deletePost;
}
}module.exports = {createPost, updatePost, deletePost}
12. After that, I create index.js
file which will export all the mutations
of GraphQL
// src/graphql/mutations/index.jsvar { addAuthor, updateAuthor, deleteAuthor } = require('./AuthorMutation');
var { createPost, updatePost, deletePost} = require('./PostMutation')module.exports = {
addAuthor,
updateAuthor,
deleteAuthor,
createPost,
updatePost,
deletePost
}
How to Create Schema in express-graphql?
Then I have create the schema
js file to src/graphql/schema.js
which contains all the graphql
Query
and Mutation
.
// src/graphql/schema.jsconst { GraphQLObjectType,GraphQLSchema } = require('graphql');
const mutation = require('./graphql/mutations/index')
const BlogQueryRootType = require('./graphql/queries/index')const BlogAppSchema = new GraphQLSchema({
query: BlogQueryRootType,
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: mutation
})
});module.exports = BlogAppSchema;
GraphQLSchema
contains thequery
andmutation
attribute or object.query
attribute containsroot type
for graphql which i created atsrc/graphql/queries/index.js
file.mutation
attribute is also aGraphQLObjectType
, which contains two attribute.
{
name: <name of the mutation>
fields: <Main mutations Object>
}
4. I have added the main mutation
objects which are exported at src/graphql/mutations/index.js
Call the Graphql Schema to http endpoint of express js:
graphql-express
which is a middleware of express and graphql.- check endpoint using
schema.js
schema atindex.js
root of the project directory.
// index.js
...
const schema = require('./src/schema');
...
...
app.use('/', graphQLHttp({
schema: schema,
graphiql: true
}));
3. Run the Application by npm start
or if you are using yarn
command will be yarn start
Query and Mutation Example
- Mutation Example for Adding the Author
2. Query Example for Show All Author
3. Mutation for update Author Information
4. Mutation for delete Author
5. Mutation for create the post info
6. Query for get all post with author data
7. Update Post Information
You will find full soruce code at