evironment and etc..
- front end: react + apollo (not inclueded in this part)
- back end: graphql + express js + mongodb
- OS: macos big sur
- Others:
- nodejs
- npm
- nodemon: server gonna update with source automatically
- repo:
backend part
server setup
-
mkdir workspace
-
cd workspace; mkdir server; cd server
-
npm install express
-
npm install nodemon
(not required optional package but if not will became really noisy for reload server every time) -
npm install graphql express-graphql
- might get error then:
npm uninstall nodemon
sudo npm install -g --force nodemon
- might get error then:
-
touch app.js
:- in app.js:
const express = require("express") const { graphqlHTTP } = require('express-graphql') const app = express() app.use('/graphql', graphqlHTTP({ })) app.listen(4000, () => { console.log('listen port 4000') })
- in app.js:
-
nodemon app
schema setup
-
mkdir schema
in server - schema.js (temporarily)
- inside of it:
-
const graphql = require('graphql') const {GraphQLObjectType, GraphQLID, GraphQLString} = graphql const MovieType = new GraphQLObjectType({ name: 'Movie', fields: () => ({ id: {type: GraphQLID}, name: {type: GraphQLString}, genre: {type: GraphQLString}, }) }) const RootQuery = new GraphQLObjectType({ name: 'RootQueryType', fields: { movie: { type: MovieType, args: {id: {type: GraphQLString}}, resolve(parents, args){ } } } })
mongodb set up
- MongoDB
- intall following packages in './server':
-
npm install express-graphql
-
npm install mongodb
-
npm install mongoose
-
- add code to
app.js
-
const express = require("express") const { graphqlHTTP } = require('express-graphql') const mongoose = require('mongoose') const app = express() mongoose.connect('mongodb+srv://<your id here>:<your pass here>@cluster0.gtgxruw.mongodb.net/?retryWrites=true&w=majority') mongoose.connection.once('open', () => { console.log('db connected') }) app.use('/graphql', graphqlHTTP({ })) app.listen(4000, () => { console.log('listen port 4000') })
-
- granqlHTTP error troubleshooting: some javascript grammer
- run
nodemon app
- got following then done
-
listen port 4000 db connected
-
query
- create records in your MongoDB Cluster DB
- add your database name in
app.js
-
mongoose.connect('mongodb+srv://.../<add your database name here>?retryWrites=true&w=majority')
-
- create model
movie.js
inserver/models
<= directory create by yourself-
const mongoose = require('mongoose') const Schema = mongoose.Schema const movieSchema = new Schema({ name : String, genre: String, }) module.exports = mongoose.model('Movie', movieSchema)
-
- add some source to app.js
-
app.use('/graphql', graphqlHTTP({ schema, graphiql: true }))
-
- add sth to
schema.js
as well-
const graphql = require('graphql') const Movie = require('../models/movie') const {GraphQLObjectType, GraphQLSchema, GraphQLID, GraphQLString} = graphql const MovieType = new GraphQLObjectType({ name: 'Movie', fields: () => ({ id: {type: GraphQLID}, name: {type: GraphQLString}, genre: {type: GraphQLString}, }) }) const RootQuery = new GraphQLObjectType({ name: 'RootQueryType', fields: { movie: { type: MovieType, args: {id: {type: GraphQLString}}, resolve(parents, args){ return Movie.findById(args.id) } } } }) module.exports = new GraphQLSchema({ query: RootQuery })
-
- finally go
http://localhost:4000/graphql
and get following stuff: some queries
mutation insert data 1/2
- add mutaion in
schema.js
-
const Mutation = new GraphQLObjectType({ name: 'Mutation', fields: { addMovie: { type: MovieType, args: { name: {type: GraphQLString}, genre: {type: GraphQLString} }, resolve(parents, args){ let movie = new Movie({ name: args.name, genre: args.genre }) return movie.save() } } } }) module.exports = new GraphQLSchema({ query: RootQuery, mutation: Mutation })
-
- test on
http://localhost:4000/graphql?
mutation insert data 2/2
- add another model (next to movie.js)
-
const mongoose = require('mongoose') const Schema = mongoose.Schema const directorSchema = new Schema({ name : String, age: Number, }) module.exports = mongoose.model('Director', directorSchema)
-
- add another mutation in
schema.js
-
const Mutation = new GraphQLObjectType({ name: 'Mutation', fields: { addMovie: { type: MovieType, args: { name: {type: GraphQLString}, genre: {type: GraphQLString} }, resolve(parents, args){ let movie = new Movie({ name: args.name, genre: args.genre }) return movie.save() } }, addDirector: { type: DirectorType, args: { name: {type: GraphQLString}, age: {type: GraphQLInt} }, resolve(parents, args){ let director = new Director({ name: args.name, age: args.age }) return director.save() } } } })
-
- and run on
http://localhost:4000/graphql
relation
- add
directorId
to movie model-
const mongoose = require('mongoose') const Schema = mongoose.Schema const movieSchema = new Schema({ name : String, genre: String, directorId: String,// }) module.exports = mongoose.model('Movie', movieSchema)
-
- add
director
toMovieType
inschema.js
& addmovie
toDirectorType
-
const MovieType = new GraphQLObjectType({ name: 'Movie', fields: () => ({ id: {type: GraphQLID}, name: {type: GraphQLString}, genre: {type: GraphQLString}, director: { // one movie has only one director type: DirectorType, resolve(parent, args) { return Director.findById(parent.directorId) } } }) }) const DirectorType = new GraphQLObjectType({ name: 'Director', fields: () => ({ id: {type: GraphQLID}, name: {type: GraphQLString}, age: {type: GraphQLInt}, movie: { // one director might has made many movies type: new GraphQLList(MovieType), resolve(parent, args) { return Movie.find({directorId: parent.id}) } } }) })
-
- add
directorId
toMutation
inschema.js
-
addMovie: { type: MovieType, args: { name: {type: GraphQLString}, genre: {type: GraphQLString}, directorId: {type: GraphQLID}, }, resolve(parents, args){ let movie = new Movie({ name: args.name, genre: args.genre, directorId: args.directorId }) return movie.save() } },
-
- drop movies from mongodb..
- and able to get the mutation result like following by now...
- and movies collection is back..
- we add another record to collection movies
- and we gonna get result of query like following
fetch a list of movies and directors
- add new queries in
schema.js
-
movies: { type: new GraphQLList(MovieType),// resolve(parent, args) { return Movie.find({}) //find means find a list in Movie } }, directors: { type: new GraphQLList(DirectorType),// resolve(parent, args) { return Director.find({}) } },
-
- list retrieved like following pic..
mutation update
- add update methods in
schema.js
-
updateMovie: { type: MovieType, args: { id: {type: GraphQLNonNull(GraphQLID)}, //.. how to add id automaticaly? name: {type: GraphQLString}, genre: {type: GraphQLString}, directorId: {type: GraphQLID} }, resolve(parent, args) { let updateMovie = {} args.name && (updateMovie.name = args.name) args.genre && (updateMovie.genre = args.genre) args.directorId && (updateMovie.directorId = args.directorId) return Movie.findByIdAndUpdate(args.id, updateMovie, {new: true}) // new: true mean enable get the result after mutated } }, updateDirector: { type: DirectorType, args: { id: {type: GraphQLNonNull(GraphQLID)}, //.. how to add id automaticaly? name: {type: GraphQLString}, age: {type: GraphQLString} }, resolve(parent, args) { let updateDirector = {} args.name && (updateDirector.name = args.name) args.age && (updateDirector.age = args.age) return Director.findByIdAndUpdate(args.id, updateDirector, {new: true}) // new: true mean enable get the result after mutated } }
-
- following able to be retrieved
mutation delete
- add delete methods in
schema.js
-
deleteMovie: { type: MovieType, args: { id: {type: GraphQLNonNull(GraphQLID)}, }, resolve(parent, args) { return Movie.findByIdAndRemove(args.id) } }, deleteDirector: { type: DirectorType, args: { id: {type: GraphQLNonNull(GraphQLID)}, }, resolve(parent, args) { return Director.findByIdAndRemove(args.id) } },
-
- removed result retrieved like following
frontend
create a react application
-
in directory of server (not in sever) create react application:
yarn create react-app client
- might failed if node version is not supported by yarn then here you go
install reactstrap, bootstrap and setup a simple page
-
in
./client
- insert
yarn add reactstrap react react-dom
- insert
npm install bootstrap
- insert
yarn add boot strap
- insert
-
do ervery ref to this commit and you can get a page like following:
intall apollo & add movie list $ add side navi
- in
./client
- insert
npm install @apollo/client graphql
- insert
yarn add @apollo/client graphql
- according to documents of apollo add everthing to app.js (fyi commit)
- if cors error then check this commit
- add movie list and side navi: fyi commit
- this page by far
- insert
intall react-hook-form: npm install react-hook-form
- and folow the step here
add mutations
refetch query (means page contents will automaticaly update after query result updated)
delete from table
-fyi