Here we want to create a simple CRUD
app with react
, GraphQL
, Node.js
and MongoDB
- part 1, let's go:
You can find source code here: source code
Project Overview
This project has two folders, server and client. In this post we just work on the server(Backend) and for the next post we will work on the client(Frontend).
Backend:
We make a GraphQL
server on node.js
by using Express
. This is where we describe how our Graph looks like, different types of data on our Graph, relationship between these data types, setting up different entry points (where we can query and retrieve information) to our Graph. And then we use MongoDB
to store our data.
Frontend:
For the client side we use React
, and also we use
Apollo
, it allows us to use GraphQL
on the frontend and inside react
.
Also, we have GraphiQL
it is like a frontend application that allows us to make a request to GraphQL
and retrieve data back.
Start working on project
1. Initialize a node project : npm init
Inside the project folder, run this command, and it is going to create a package.json
file for us.
2. Inside project folder we should create a folder and call it to server, all of our server side code will be inside this folder.
3. Create an express application: npm install express
4. Create index.js file
Inside this file we:
- Set up our
express app
and listen to a specific port(5000). - Set up our
GraphQL
.we need to install two package:npm install graphql express-graphql
.first one is the maingraphql
package which is aJavaScript
implantation ofGraphQL
, the second one is a package that help our express app to interact withGraphQL
becauseexpress
doesn't understandGraphQL
(requireexpress-graphql
module(grapqlHTTP
)). - Setup some middleware. The way that we do that in express is by using app.use(). Like this one :
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}));
Here we say the route that we gonna use on this middleware is /graphql
and then fire a function. when a request to/graphql
comes in and this function going to handle our GraphQL
requests, and it takes some options inside an object. We have to pass schema
and graphiql: true
as a property to this middleware.
Schema
, going to tell express graphql
about our data and how graph will looks like.it says what data types are in the graph and relationship between them.
5. Create Schema.js file
schema
has three responsibility:
define Object Type
, define relationship between Object Type
, define rootQuery
.
Create a
Schema
to describe how the data in our graph will looks like, inside this file we're going to define our schema.
Schema
describe theobject type
and the relations between theseobject types
, how we can read data and interact with them.Require the
GraphQL
. We install this package before.We define
ObjectType
and define what thisObjectType
is about (define name & fields)
Here, we just define one object type:TodoType
.
const TodoType = new GraphQLObjectType({
name: 'Todo',
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString }
})
});
The GraphQLObjectType
is a function and takes in an object and this object going to define what this TodoType
is all about.
name
: a name for our object type.
fields
:it is a function that returns an object, it's define the fields on this TodoType
and then say what type is our fields.
6. Create RootQuery
RootQeury
:it is our entry point to the graph. How we describe, a user can initially jump to the graph and grab data.We define
fields
of thisRoot Query
and each of this fields going to be a type ofRootQuery
.first one is going to be a query for list oftodos
and the second is for onetodo
and the argument that we expected to get along with this query isid
.Also, we have type and resolve function for each field.
resolve
function : how to get data when someone requested.it is for grabbing data and return what is needed.
this resolve function takes two parameters :parent
&args
.parent
coming to play when we start relationship between data.
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: () => ({
todos: {
type: new GraphQLList(TodoType),
resolve(parent, args) {
return Todo.find();
}
},
todo: {
type: TodoType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return Todo.findById(args.id);
}
}
})
});
7. Connect to database
To connect to the database, create a folder called config
and then create db.js
file inside it: server/config/db.js
.
inside db.js
file, first we bring mongoose to connect:
const mongoose = require('mongoose');
Second we have an async function called connectDB
(because mongoose functions return promises) and then on the connect
we pass our mongoose URL.
const connectDB = async () => {
const conn = await mongoose.connect('');
console.log(`mongoDB connected : ${conn.connection.host}`);
};
After that, we call this connectDB
function inside index.js
:
//connect to database
connectDB();
8. Mongoose Model
Create a
models
folder and then inside it createTodo.js
file :server/models/Todo.js
.Here we're going to store our
mongoose models
.This
model
represents different types of collection in ourMongoDB
instance.Mongoose schema
, going to define the data that actually being stored inMongoDB
and this is going to take an object with the fields that we want.In our code, we use
Todo
model.thisTodo model
means how we interact with the todo collection then we use a method on it:
return Todo.find();
return Todo.findById(args.id);
9. Mutations
It allows us to change or mutate data like add, delete, edit data. We define our
mutation
inschema.js
file.Setting-up a mutation is like setting-up our
RootQuery
. We pass throw an object toGraphQLObjectType
and this is going to have two property:name
,fields
.
This fields property let us store different kind of mutations that we want to make likeaddTodo
,editTodo
,deleteTodo
, ....
// Add todo
addTodo: {
type: TodoType,
args: {
title: { type: GraphQLNonNull(GraphQLString) },
},
resolve(parent, args) {
const todo = new Todo({
title: args.title
});
return todo.save();
}
},
For example: this addTodo
property is going to be an object
and takes these properties:type
and args
.
args
: when a user makes a mutation from the frontend, then we expect them to send some kind of data or arguments.
Here, if a user wants to add a todo
they're going to need send the todo
title.(the fields that we want to add)
resolve
: this function is where we take the argument that they send along the query. By using Todo model
that, we import it before We make a new instance of todo and save it to the database.
Code:
index.js - server/index.js
const { graphqlHTTP } = require('express-graphql');
const express = require('express');
const schema = require('./schema/schema');
const app = express();
const connectDB = require('./config/db');
const cors = require('cors');
//connect to database
connectDB();
app.use(cors());
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}));
app.listen(5000, () => {
console.log('now listening for requests on port 5000');
});
schema.js - server/schema/schema.js
const {
GraphQLObjectType,
GraphQLID,
GraphQLString,
GraphQLSchema,
GraphQLList,
GraphQLNonNull
} = require('graphql');
//Mongoose models
const Todo = require('../models/Todo.js')
//todos Typeo
const TodoType = new GraphQLObjectType({
name: 'Todo',
fields: () => ({
id: { type: GraphQLID },
title: { type: GraphQLString }
})
});
const RootQuery = new GraphQLObjectType({
name: 'RootQueryType',
fields: () => ({
todos: {
type: new GraphQLList(TodoType),
resolve(parent, args) {
return Todo.find();
}
},
todo: {
type: TodoType,
args: { id: { type: GraphQLID } },
resolve(parent, args) {
return Todo.findById(args.id);
}
}
})
});
// Mutations
const mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
// Add todo
addTodo: {
type: TodoType,
args: {
title: { type: GraphQLNonNull(GraphQLString) },
},
resolve(parent, args) {
const todo = new Todo({
title: args.title
});
return todo.save();
}
},
// Delete Todo
deleteTodo: {
type: TodoType,
args: {
id: { type: GraphQLNonNull(GraphQLID) },
},
resolve(parent, args) {
return Todo.findByIdAndRemove(args.id)
}
},
// Edit Todo
editTodo: {
type: TodoType,
args: {
id: { type: GraphQLNonNull(GraphQLID) },
title: { type: GraphQLString },
},
resolve(parent, args) {
return Todo.findByIdAndUpdate(
args.id,
{
$set: {
title: args.title,
},
},
{ new: true }
);
},
},
}
})
module.exports = new GraphQLSchema({
query: RootQuery,
mutation
})
Todo.js- server/models/Todo.js
const mongoose = require('mongoose');
const TodoSchema = new mongoose.Schema({
title: {
type: String,
}
});
module.exports = mongoose.model('Todo', TodoSchema);
db.js - server/config/db.js
const mongoose = require('mongoose');
const connectDB = async () => {
const conn = await mongoose.connect('');
console.log(`mongoDB connected : ${conn.connection.host}`);
};
module.exports = connectDB;
Now here we go! We created a simple CRUD
app with react
, GraphQL
, Node.js
and MongoDB
. In the below I put links that are helpful for me to create this project:
By the way The link to the front end section will be posted here soon!
The GraphQL tutorial playlist on The Net Ninja YouTube channel.
Full stack GraphQL, Express & React app - Traversy Media
Thank you for reading! 🍀
Top comments (0)