DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

vinodchauhan7
vinodchauhan7

Posted on • Updated on

MERN App using GraphQL via Apollo-Client,(React Hooks). (Part-2)

Today we will start second part of this article series for creating mern app using graphql. In part-1, we have made progress upto extracting data from our queries, now we will proceed further on this.

GitHub Link : MERN-app-using-graphql-apollo-client

Now we first define the relations between the Car and owner. And how details can be fetched.

a) Type Relations

1) At first, We give 'ownerId' to each car.
2) Define the relations of car with unique owner in 'CarType'.
3) Define the list of cars with each Owner with ownerId in Owner Type.
4) Cars and Owners Query in rootQuery.

 //Schema.js
const graphql = require("graphql"); //use graphql package

const _ = require("lodash");

/*Getting GraphQLObjectType function from 'graphql' to define the (dataType) 
 structure of our queries and their model type.
*/
const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema,
  GraphQLList
} = graphql;

const CarsArray = [
  { id: "1", name: "S-Class", model: "2019", company: "Mercedes" ,ownerId : "1"},
  { id: "2", name: "Continental GT", model: "2019", company: "Bentley",ownerId : "2" },
  { id: "3", name: "Phantom", model: "2019", company: "Rolls-Royce",ownerId : "1" },
  { id: "4", name: "Panamera", model: "2019", company: "Porsche" ,ownerId : "2"},
  { id: "5", name: "A8", model: "2019", company: "Audi" ,ownerId : "1"},
  { id: "6", name: "I-Pace", model: "2019", company: "Jaguar",ownerId : "3"}
];

var OwnersArray = [
  { id: "1", name: "Vinod Chauhan", age: 27, gender: "male" },
  { id: "2", name: "John Dow", age: 46, gender: "male" },
  { id: "3", name: "Kristen", age: 30, gender: "female" },
  { id: "4", name: "Paris", age: 44, gender: "female" },
  { id: "5", name: "Sylvestor", age: 26, gender: "male" }
];

//Defining CarType with its fields.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString },
    owner : { //Supporting pwner query in carType
        type: OwnerType,
        resolve(parent,args){
           return _.find(OwnersArray,{id:parent.ownerId});
        }
    }//owner 
  })
});

//Defining CarType with its fields.
const OwnerType = new GraphQLObjectType({
  name: "Owner",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    gender: { type: GraphQLString },
    cars : {  // Supporting list of cars query in Owner type
        type : new GraphQLList(CarType),
        resolve(parent,args){
            return _.filter(CarsArray,{ownerId : parent.id});
        }
    }
  })
});

//Defining RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Fields here will be the query for frontends
    //We are defining a 'car' query which can take (car ID ) to search in DB.
    car: {
      type: CarType, //Defining model for car Query
      args: { id: { type: GraphQLID } }, //args field to extract
      // argument came with car query, e.g : Id of the car object to extract its details.
      resolve(parent, args) {
        //code to get value  from DB
        /**
         * With the help of lodash library(_), we are trying to find car with id from 'CarsArray'
         * and returning its required data to calling tool.
         */
        return _.find(CarsArray, { id: args.id });
      } //resolve function
    }, //car query ends here
    owner: {
      type: OwnerType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return _.find(OwnersArray, { id: args.id });
      }
    },//owners ends here
    cars : {
        type : new GraphQLList(CarType),
        resolve(parent,args){
            return CarsArray;
        }
    },//cars query
    owners : {
        type : new GraphQLList(OwnerType),
        resolve(parent,args){
            return OwnersArray;
        }
    }
  } //fields end here
});

//exporting 'GraphQLSchema with RootQuery' for GraphqlHTTP middleware.
module.exports = new GraphQLSchema({
  query: RootQuery
});


You can see result like this.

Alt Text

Alt Text

Hope you all got understanding of graphql upto this point and now we will connect with mongoDB(Database).

For Database, we will use online mongoDB server mlab www.mlab.com. Those who don't know what is mlab and how to create database & credentials on it, then please look for any youtube video you will get your all answers.

b) Database Connectivity

To connect with mlab server(mongoDB) we will use mongoose package.

//In app.js
//Get the express library from node_modules which we have just downloaded.
const express = require("express");

const graphqlHTTP = require("express-graphql");

const mongoose = require("mongoose"); //using mongoose to connect with db

//Imports
const schema = require("./schema/schema");

//Making const of express() into a variable (JS function first class Object).
const app = express();

//Please change mongoDB connection as maybe I have deleted this db on mlab when you are using it.
mongoose.connect(
  "mongodb://test:test123@ds145434.mlab.com:45434/gql-practice",
  { useNewUrlParser: true },
  () => {
    console.log("Connect with DB successfully.");
  }
);

/*We can use graphql on express server with middlewares, so that whenever
    we need graphql query from frontend, our express server can handle it
    smoothly.
*/
app.use(
  "/graphql",
  graphqlHTTP({
    schema: schema,
    graphiql: true
  })
);

//When our application starts, it will listen on port 4000
app.listen(4000, () => {
  console.log("Server is listening on port 4000");
});

Output on terminal

//Output on console
[nodemon] restarting due to changes...
[nodemon] starting `node .\app.js`
Server is listening on port 4000
Connect with DB successfully

C) Creating models for mongoDB.

Here we need to create models of carType and OwnerType which mongoDB can understand, which enables us to save our record in it.
1) Create 'models' folder inside 'server' folder.
2) Create file 'Car' model to store different car details.
3) Create file 'Owner' model to store differet owner details.

  //car.js
const mongoose = require("mongoose");

const CarSchema = new mongoose.Schema({
  name: String,
  model: Number,
  company: String,
  ownerId: String
});

module.exports = mongoose.model("cars", CarSchema);


//---------------------------------------------------------

//owner.js
const mongoose = require("mongoose");

const ownerSchema = new mongoose.Schema({
  name: String,
  age: Number,
  gender: String
});

module.exports = mongoose.model("owners", ownerSchema);

d) Understanding CRUD 'MUTATIONS' in GraphQL.

To implement crud implementation in graphql we need to understand mutations in it.
Mutation is an object type of GraphQLObjectType() in which we can add different operations like addCar, addOwner & so on.

  //schema.js

const graphql = require("graphql"); //use graphql package

const _ = require("lodash");

const cars = require("../models/car");
const owners = require("../models/owner");

/*Getting GraphQLObjectType function from 'graphql' to define the (dataType) 
 structure of our queries and their model type.
*/
const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema,
  GraphQLList
} = graphql;

//Defining CarType with its fields.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString },
    owner: {
      type: OwnerType,
      resolve(parent, args) {
        // return _.find(OwnersArray, { id: parent.ownerId });
      }
    } //owner
  })
});

//Defining CarType with its fields.
const OwnerType = new GraphQLObjectType({
  name: "Owner",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    gender: { type: GraphQLString },
    cars: {
      type: new GraphQLList(CarType),
      resolve(parent, args) {
        //return _.filter(CarsArray, { ownerId: parent.id });
      }
    }
  })
});

//Defining RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Fields here will be the query for frontends
    //We are defining a 'car' query which can take (car ID ) to search in DB.
    car: {
      type: CarType, //Defining model for car Query
      args: { id: { type: GraphQLID } }, //args field to extract
      // argument came with car query, e.g : Id of the car object to extract its details.
      resolve(parent, args) {
        //code to get value  from DB
        /**
         * With the help of lodash library(_), we are trying to find car with id from 'CarsArray'
         * and returning its required data to calling tool.
         */
        //return _.find(CarsArray, { id: args.id });
      } //resolve function
    }, //car query ends here
    owner: {
      type: OwnerType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        // return _.find(OwnersArray, { id: args.id });
      }
    }, //owners ends here
    cars: {
      type: new GraphQLList(CarType),
      resolve(parent, args) {
        //return CarsArray;
      }
    }, //cars query
    owners: {
      type: new GraphQLList(OwnerType),
      resolve(parent, args) {
        //return OwnersArray;
      }
    }
  } //fields end here
});

const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
    addOwner: {    // To add Owner in DB
      type: OwnerType,
      args: {
        name: { type: GraphQLString },
        age: { type: GraphQLInt },
        gender: { type: GraphQLString }
      },
      resolve(parent, args) {
        let owner = new owners({
          name: args.name,
          age: args.age,
          gender: args.gender
        });
        return owner.save(); //create owner data in mlab
      }
    }
  } //fields ends here
});

//exporting 'GraphQLSchema with RootQuery' for GraphqlHTTP middleware.
module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation
});

In above screenshot, we have done following steps to connect our graphQL-Express server with mongoDb :
1) Import cars & owners model in it.
2) Remove dummy Data.
3) Comment out all returns as we will get data from db now.
4) Create a new Object mutations(means to mutate something) to implement our crud logic.
5) Add entry of Mutation object in GraphQLSchema.

Open localhost:4000/graphql, Here on the right side you will new entry mutation.

Alt Text

Alt Text

Similarly do above steps for adding 'addCar' after 'addOwner' mutation.

 addCar: {
      type: CarType,
      args: {
        name: { type: GraphQLString },
        model: { type: GraphQLInt },
        company: { type: GraphQLString },
        ownerId: { type: GraphQLID }
      },
      resolve(parent, args) {
        let car = new cars({
          name: args.name,
          model: args.model,
          company: args.company,
          ownerId: args.ownerId
        });

        return car.save();
      }
    }//addCar

Alt Text

e) Update Resolve function for all queries

const graphql = require("graphql"); //use graphql package

const _ = require("lodash");

const cars = require("../models/car");
const owners = require("../models/owner");

/*Getting GraphQLObjectType function from 'graphql' to define the (dataType) 
 structure of our queries and their model type.
*/
const {
  GraphQLObjectType,
  GraphQLID,
  GraphQLString,
  GraphQLInt,
  GraphQLSchema,
  GraphQLList
} = graphql;

//Defining CarType with its fields.
const CarType = new GraphQLObjectType({
  name: "Car",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    model: { type: GraphQLInt },
    company: { type: GraphQLString },
    owner: {
      type: OwnerType,
      resolve(parent, args) {
        return owners.findById(parent.ownerId);
      }
    } //owner
  })
});

//Defining CarType with its fields.
const OwnerType = new GraphQLObjectType({
  name: "Owner",
  fields: () => ({
    id: { type: GraphQLID },
    name: { type: GraphQLString },
    age: { type: GraphQLInt },
    gender: { type: GraphQLString },
    cars: {
      type: new GraphQLList(CarType),
      resolve(parent, args) {
        return cars.find({ ownerId: parent.id });
      }
    }
  })
});

//Defining RootQuery
const RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    // Fields here will be the query for frontends
    //We are defining a 'car' query which can take (car ID ) to search in DB.
    car: {
      type: CarType, //Defining model for car Query
      args: { id: { type: GraphQLID } }, //args field to extract
      // argument came with car query, e.g : Id of the car object to extract its details.
      resolve(parent, args) {
        //code to get value  from DB
        /**
         * With the help of lodash library(_), we are trying to find car with id from 'CarsArray'
         * and returning its required data to calling tool.
         */
        return cars.findById(args.id);
      } //resolve function
    }, //car query ends here
    owner: {
      type: OwnerType,
      args: { id: { type: GraphQLID } },
      resolve(parent, args) {
        return owners.findById(args.id);
      }
    }, //owners ends here
    cars: {
      type: new GraphQLList(CarType),
      resolve(parent, args) {
        return cars.find({});
      }
    }, //cars query
    owners: {
      type: new GraphQLList(OwnerType),
      resolve(parent, args) {
        return owners.find({});
      }
    }
  } //fields end here
});

const Mutation = new GraphQLObjectType({
  name: "Mutation",
  fields: {
    addOwner: {
      type: OwnerType,
      args: {
        name: { type: GraphQLString },
        age: { type: GraphQLInt },
        gender: { type: GraphQLString }
      },
      resolve(parent, args) {
        let owner = new owners({
          name: args.name,
          age: args.age,
          gender: args.gender
        });
        return owner.save();
      }
    }, //AddOwner ends here
    addCar: {
      type: CarType,
      args: {
        name: { type: GraphQLString },
        model: { type: GraphQLInt },
        company: { type: GraphQLString },
        ownerId: { type: GraphQLID }
      },
      resolve(parent, args) {
        let car = new cars({
          name: args.name,
          model: args.model,
          company: args.company,
          ownerId: args.ownerId
        });

        return car.save();
      }
    } //addCar
  } //fields ends here
});

//exporting 'GraphQLSchema with RootQuery' for GraphqlHTTP middleware.
module.exports = new GraphQLSchema({
  query: RootQuery,
  mutation: Mutation
});

open localhost:4000/graphql , do your queries on it.

Alt Text

Code Structure

Alt Text

Congratulations!! We have just made our express-graphql server with mongoDB. In next part, we will create frontEnd client(react + apollo-client) to hit this queries. Till then bye guys & have fun.

Top comments (2)

Collapse
 
paramharrison profile image
Paramanantham Harrison • Edited on

Very good series Vinod.

Your flow was excellent, keep it up

Few suggestions,

  • don’t paste image screenshot, instead put the query and result in a code block which will make it easy to copy for others and view it even on mobile easily
  • don’t show the whole code of a file every time, it has more repeated code. Instead show the exact code. For example, show only mutation and add it to rootSchema instead of showing the whole file. It will be confusing to go through once the file become huge

That said, you should teach more series πŸ™Œ

Collapse
 
vinodchauhan7 profile image
vinodchauhan7

Thanx Paramanantham for the appreciation, In next articles, I will keep in mind about your suggestions.

Let's Get Hacking

Join the DEV x Linode Hackathon 2022 and use your ingenuity and creativity to build using Linode.

β†’ Join the Hackathon <-