CRUD Operation with React Native and GraphQL Server

This is third part of React Native and GraphQL series. If you haven’t checked previous part, please check it here. In the last part we coded CRUD operation for GraphQL client and used Graphcool as GraphQL server. If you check my first tutorial on GraphQL, I mentioned that we can implement our own GraphQL server. I started learning Graphql because it allows us to implement our own server which I was missing with firebase. Implementing a standalone technology (i.e. having control of both client and server ), is an achievement in itself. So, in this part of tutorial we will learn how we can implement our own GraphQL server and make our GraphQL client work with it.

Our Graphql server will have three parts/layers :

  1. Schema
  2. Resolvers
  3. Connectors

Schema is very similar to database schema we were creating for Graphcool server. But here we have to specify the structure of our database model, queries and mutation.

Resolvers establish relationship between Schema and Connectors.

Connectors establish connection between resolvers and database.

I am using Sqlite database here, but,  you can use mongodb, MySql or any other supported database.

First, create a directory gqlserver.  Inside it, create a file package.json and copy the content below in it.

{
  "name": "gqlserver",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "nodemon ./server.js --exec babel-node",
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint": "eslint ."
  },
  "author": "Dev Abhi",
  "license": "ISC",
  "dependencies": {
    "apollo-server-express": "^1.0.2",
    "body-parser": "^1.17.2",
    "casual": "^1.5.17",
    "cors": "^2.8.4",
    "express": "4.13.4",
    "graphql-tools": "^1.0.0",
    "lodash": "^4.17.4",
    "sequelize": "^4.19.0",
    "sqlite": "^2.8.0"
  },
  "devDependencies": {
    "babel-cli": "6.5.1",
    "babel-core": "^6.5.2",
    "babel-eslint": "^6.0.0-beta.6",
    "babel-polyfill": "6.5.0",
    "babel-preset-es2015": "6.5.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-stage-0": "6.5.0",
    "eslint": "^2.4.0",
    "eslint-config-airbnb": "^6.1.0",
    "eslint-plugin-import": "^1.1.0",
    "eslint-plugin-react": "^4.2.3",
    "graphql": "^0.10.0",
    "nodemon": "^1.9.1"
  },
  "peerDependencies": {
    "graphql": "^0.5.0 || ^0.6.0"
  },
  "eslintConfig": {
    "parser": "babel-eslint",
    "extends": [
      "airbnb/base",
      "plugin:import/errors"
    ],
    "rules": {
      "no-use-before-define": 0,
      "arrow-body-style": 0,
      "dot-notation": 0,
      "no-console": 0
    },
    "env": {
      "mocha": true
    }
  }
}

So, your package.json file should look like above with all the dependencies we need to create graphql server.

Next, create a file .babelrc and add the content below :

{
  "passPerPreset": true,
  "presets": [
    "react",
    "es2015",
    "stage-0"
  ],
  "plugins": [
  ]
}

Adding the above file will allow us to use ecma6 syntax in our server code.

Now fire the command below to install all dependencies :

npm install

Create a file server.js and add the code below :

import express from 'express';
import { graphqlExpress, graphiqlExpress } from 'apollo-server-express';
import bodyParser from 'body-parser';
import schema from './data/schema';
import cors from 'cors';

const GRAPHQL_PORT = 4000;

const graphQLServer = express();
graphQLServer.use('*', cors({ origin: 'http://192.168.1.3:8081' }));
graphQLServer.use('/graphql', bodyParser.json(), graphqlExpress({ schema }));
graphQLServer.use('/graphiql', graphiqlExpress({ endpointURL: '/graphql' }));


graphQLServer.listen(GRAPHQL_PORT, () => console.log(
  `GraphiQL is now running on http://localhost:${GRAPHQL_PORT}/graphiql`
));

In the above code we have created a GraphQL Server using express and graphql on port 4000. Cors will allow client from different ip or port to connect to the server.

Create a file schema.js and add the code below :

import {
  makeExecutableSchema,
  addMockFunctionsToSchema,
} from 'graphql-tools';

import resolvers from './resolvers';

const typeDefs = `
type User {
  id: Int
  firstName: String
  lastName: String
}
type Query {
  user(firstName: String, lastName: String): User
  allUsers: [User]
}
type Mutation {
  createUser(firstName: String!, lastName: String!): User
  deleteUser(id: Int!): User
  updateUser(id: Int!, firstName : String!, lastName: String!): User
}
`;

export default makeExecutableSchema({ typeDefs, resolvers });

In the above code we have created schema of type User, Query and Mutation, structure of which , is as per requirement of our client app. Our client app requirements are to list all users , create users, delete users and update users detail.

Create a file resolvers.js and add the code below :

import { User } from './connectors';

const resolvers = {
  Query: {
    user(_, args) {
      return User.find({ where: args });
    },
    allUsers: () => {
      return User.all();
    }
  },
  Mutation: {
    createUser: (_, data) => {
      const ret = User.create({
        firstName: data.firstName,
        lastName: data.lastName,
      })
      return ret
    },
    deleteUser: (_,args)=> {
      User.destroy({ where: args });
      return { id : args.id}
    },
    updateUser: (_,args)=> {
      User.update({  firstName: args.firstName,lastName: args.lastName },{ where: { id: args.id } });
      return { id: args.id, firstName: args.firstName,lastName: args.lastName}
    }
  }
};

export default resolvers;

In the above code, we are importing User model from connectors and resolving queries and mutations specified in Schema we created above.

Finally create file connectors.js and add the code below :

import Sequelize from 'sequelize';
import casual from 'casual';
import _ from 'lodash';

const db = new Sequelize('blog', null, null, {
  dialect: 'sqlite',
  storage: './blog.sqlite',
});

const UserModel = db.define('user', {
  firstName: { type: Sequelize.STRING },
  lastName: { type: Sequelize.STRING },
});

casual.seed(123);
db.sync({ force: true }).then(() => {
  _.times(10, () => {
    return UserModel.create({
      firstName: casual.first_name,
      lastName: casual.last_name,
    })
  });
});

const User = db.models.user;


export { User };

In the above code we are creating database and User Model using Sqlite and Sequelize and adding some dummy data using casual module.

Now lets make a small modification to our client side code so that it works with our new server :

import React from 'react'
import { ApolloProvider, createNetworkInterface, ApolloClient } from 'react-apollo'
import Createuser from './components/Createuser'

//const networkInterface = createNetworkInterface({ uri: 'https://api.graph.cool/simple/v1/cj8h0xusx000p01288nf9eemh' })
const networkInterface = createNetworkInterface({ uri: 'http://192.168.1.3:4000/graphql' })

const client = new ApolloClient({ networkInterface })

export default (
  <ApolloProvider client={client}>
    <Createuser />
  </ApolloProvider>
)

In the above code, we have commented the createNetworkInterface uri having graphql url and added our new server url to it.

Go gqlserver directory in command prompt and fire the command belwo to start server

npm start

Now, start ReactGraphQLApp app and it will perform all CRUD operations like before, without connection to any third party server, because, now it’s connected to your own server 😉

Video Tutorial