How to Create Application in React Native with Node.js backend and GraphQL
I will explain every topic with an example with minimum complexity that helps you to build a cross-platform application with a backend.
⇒ In this example , we will use React Native(for App), Node.Js(Backend API), & MongoDB(for database).
What is React Native?
If you are new to React Native, then learn from: https://reactnative.dev/
Set up Environment for React Native
I hope you are ready with React Native environment set up, if not then please visit: https://reactnative.dev/docs/environment-setup
How to create a basic API in Node.Js backend?
I will explain this with an example, but you want to know only Node.Js backend API then visit: https://www.section.io/engineering-education/building-a-basic-api-with-nodejs/
Set up Environment for Node.Js
I hope you are also ready with the Node.Js environment setup. It only requires installing node & npm, visits: https://nodejs.org/en/
Set up Environment for MongoDB
Visit MongoDB’s official website & follow the steps to set up MongoDB on your local PC, or you can use the cloud database of MongoDB Alas. visit: https://docs.mongodb.com/manual/installation/
What is GraphQL?
GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.
In simple language, if I explain, GraphQL works as a carrier of data between Backend & Frontend, which means we will create API in Node.Js & Application in React Native as usual, but to call Rest APIs we will use GraphQL instead of manual calling with Axios or fetch. If you want more details, then visit: https://graphql.org/learn/
Start MongoDB, Create backend project, Install required libraries & Implement Backend code
Now we are ready to start after all environments are set up
Here we are going to build an Application with a frontend & backend. So first we will start to develop basic backend APIs for Book & Author. We will not implement complicated things. So let’s start.
So let’s start
Here I am assuming you have completed all the setup. After that, we will follow steps to start MongoDB in the local machine( I am doing all the things in MacOs)
Step-1: Open terminal and this fire below command to in MongoDB directory.
cd /usr/local/var/log/mongodb [if Intel Processor] cd /opt/homebrew/var/log/mongodb [if Apple M1 Processor]
Step-2: Fire the below command to start the MongoDB database server locally brew services start [email protected] After your work is done, if you want to stop MongoDB then fire the below command in the same path brew services stop [email protected]
Step-3: Here we will start to create APIs in Node.Js & Connect the MongoDB database.
- Create a folder for your project I named “LibraryM_backend”, you can name anything as you want.
- Open that folder path in terminal & fire command npm init -y. After this command, you can see a package.json file in your folder. And after that, we will install all required libraries (npm packages)
- We will install the below packages.
- npm install mongoose
- npm install express
- Create an index.js file in the root directory of a project like “/LibraryM_backend/index.js” and paste the following code.
const express = require('express'); const mongoose = require('mongoose'); const app = express(); //Establish database connection const connectDb = async () => { await mongoose.connect('mongodb://localhost:27017/book_db', { useUnifiedTopology: true, useNewUrlParser: true }).then(() => { console.log("DB connected successfully...."); }).catch(() => { console.log("DB connection failed..."); }) } connectDb() //listening server on port 4000 app.listen(4000, () => { console.log("Server is running on port: 4000"); })
- mongoose.connect is connecting to the “book_db” MongoDB database. If that is already created then that connects with existing otherwise create a new one & then connect “mongodb://localhost:27017/book_db” is a connection string to connect with the MongoDB database.
- Run command npm start & you will find in console “Server is running on port: 4000”.
- Here every time we will need to start the server after changes to get reflect changes, to avoid this we need to install a dev dependency nodemon: npm install –save-dev nodemon
- Change the following code in package.json
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "nodemon server.js" },
- Now we are done with the database connection & server started.
Integrate GraphQL in backend side (Using Apollo Server)
After we will install npm for GraphQL
npm install apollo-server
npm install graphql
What is Apollo Server?
Apollo Server is an open-source, spec-compliant GraphQL server that’s compatible with any GraphQL client, including Apollo Client. It’s the best way to build a production-ready, self-documenting GraphQL API that can use data from any source.
In simple language, Apollo Server is used in Backend Side and Apollo Client is used in Frontend Side(React JS, React Native, or any other frameworks). So Apollo Client makes it enabled to interact with backend APIs.
Create folder structure for backend
I will create a folder structure like below. You can create according to your convenience.
Configure Apollo Server, Connect to DB & Start Server
Now time to integrate GraphQL with backend in index.js file
const express = require('express'); const mongoose = require('mongoose'); const { ApolloServer } = require('apollo-server-express'); //Resolvers const BookResolver = require('/src/resolvers/BookResolver'); const AuthorResolver = require('/src/resolvers/AuthorResolver'); const UserResolver = require('/src/resolvers/UserResolver'), ; //Type Defs const AuthorTypedef = require('/src/typesDefs/AuthorTypeDef'); const BookTypedef = require('/src/typesDefs/BookTypeDef'); const UserTypedef = require("./src/typesDefs/UserTypedef'); // function to create graphql apollo server async function startServer() { const app = express(); const apolloServer = new ApolloServer({ typeDefs: [BookTypeDef, Author TypeDef, UserTypeDef], resolvers: [BookResolver, AuthorResolver, UserResolver), context: async ({ reg }) => { }, }); // Start grapql server await apolloServer.start(); // Apply express (app) as middleware await apolloServer.applyMiddleware({ app: app }); // MongoDb database connection await mongoose.connect('mongodb://localhost:27017/book_db', { useUnifiedTopology: true, useNewUrlParser: true }) console.log("Mongodb connected ........"); app.listen(4000, () => { console.log("Server is running on port: 4000"); startServer(); }) } startServer()
Explanation of GraphQL Keywords
In the above code, you can see how GraphQL can be configured & start.
I think you are familiar with express & mongoose, and now ApolloServer. There are three keywords used here “typeDefs” & “resolvers”, the next “context” that will need to be explained.
typeDefs: Document or documents that represent your server’s GraphQL schema.
That needs to pass in typeDefs props while creating ApolloServer. A typeDefs looking like
const { gql } = require('apollo-server-express'), const BookTypedef = gql` # AuthorInput type Author { id: ID authorName: String description: String email: String } # Book type Book { id: ID title: String bookescription: String publishedYear: Int author: Author, bookImage: File } type Query { getAllBooks: [Book] getBooksByAuthor(id: ID): [Book] getSingleBook(id:ID): Book } input BookInput { title: String bookdescription: String publishedYear: Int author: String } type Mutation { createBook (book: BookInput): Book updateBook(id: String, book: BookInput) : Book deleteBook (id: String): String deleteAllBook: String } ` module.exports = BookTypeDef
Explanation:
-
“Mutation”:
- Mutation queries modify data in the data store and return a value. It can be used to insert, update, or delete data. In the above code inside Mutation, there are declared methods, “createBook(book:BookInput): Book” & others for an update, delete, delete all are called “mutation” that is used in resolver where we will perform actual database operation & return data.
-
“resolvers”:
- A resolver is a function that’s responsible for populating the data for a single field in your schema. This means actual operations are performed( get, or update data in database) in resolver & return response. “Resolvers” are defined in the/src/resolvers folder.
-
“Query”:
- A GraphQL query is used to read or fetch values, which means to perform the “GET” method, we can use query.
- “Book” & “Author”:
- “Book” & “Author” are types that contain which fields are allowed to send as a response. It is user-defined, & we need the “type” keyword to define it.
- “BookInput”:
- “BookInput” is an input type that contains what fields we are going to receive in the request body.
- Note: If we declare any field as “äuthorName”: String! It indicates the required field.
// BookModal that defined for MongoDB Book Schema. const Book = require('../models/BookModal'); const BookResolver = { Query: { getAllBooks: async (parent, args, context, info) => { return await Book.find().populate("author"); }, getSingleBook: async (parent, args, context, info) => { return await Book.findById(args.id).populate("author"); } getBooksByAuthor: async (parent, args, context, info) => { let books = await Book.find({ author: args.id }) return books; } } Mutation: { createBook: async (parent, args, context, info) => { const book = new Book(args.book); await book.save(); return book; } updateBook: async (parent, args, context, info) => { const { id } = args const book = await Book.findByIdAndUpdate(id, args.book); return book; } deleteBook: async (parent, args, context, info) => { const { id } = args await Book.findByIdAndDelete(id) console.log("Book deleted successfully"); return "Book deleted successfully"; } deleteAllBook: async (parent, args, context, info) =>{ await Book.deleteMany() return "Books deleted successfully"; } }} module.exports = BookResolver
- Explanation:
- It is a resolver for “Book”, in this, we defined Query, & Mutation’s methods that were declared in typeDefs. You can understand better by looking at the above image, let’s see.
Mutation: { createBook: async (parent, args, context, info) => { const book = new Book(args.book); await book.save(); return book; } }
- All parameters (parent, args, context, info) are predefined & are explained very well in the doc: https://graphql.org/learn/execution/
- The operations which were performed in the controller to insert or update data into the database, perform here in the resolver for particular operations.
- : Hereafter save data into the database, it is returning a “book” object & “book” object may have many fields value, but because of graphQL, it will check “Book” type in typeDefs & return only those filed that will match in Book type.
Query: { getAllBooks: async (parent, args, context, info) => { return await Book.find().populate("author"); } }
- Here all methods that are declared in typeDefs’ Query are defined. It performs fetch operations & returns “Book” objects with only those fields which are declared in “Book” type in typeDefs.
- “Configure GraphQL Apollo Server”:
- : After creating typeDefs & resolver, We will create Apollo Server & start that.
const apolloServer = new ApolloServer({ typeDefs: [BookTypeDef, Author TypeDef, UserTypeDef], resolvers: [BookResolver, AuthorResolver, UserResolver), context: async ({ reg }) => { }, });
- in the above image, you can see “context”. It can be used to handle authentication-based API calls. This means inside that we can verify user credential & header’s auth token before going in the resolver, & can throw Authentication error from here, and in the resolver, there is a parameter “context” that contains login user information. We can throw errors if not get user data.
Creating React Native project & Implement GraphQL (Apollo Client)
- Step-1: Now finally, We are done with the backend all stuff
- Create a React Native app : npx react-native init LibraryM_frontend
- Step-2: Open App in VS code & install required npm packages
- For Navigation, you can use the react-navigation library:
- https://reactnavigation.org/docs/getting-started/
- npm install @apollo/client graphql
There are two libs needed to install “@apollo/client” & “graphql”.
- Step-3: You can create a folder structure like below.
Create folder structure for React Native app (Frontend)
Write queries & mutations in the book.js file, that will be used to fetch & update data.
The below image represents “query” which means fetch operations.
Integrate & Configure GraphQL in React Native App (Apollo Client)
import { gql, useMutation } from '@apollo/client' // Queries const GET_ALL_AUTHOR = gql` query getAllAuthors { getAllAuthors { id authorName description email } } `; const GET_SINGLE_AUTHOR = gql` query getSingleAuthor { getSingleAuthor { id authorName description email } } `;
The below image represents the insert operation, similarly, we can write for the update & delete.
import {gql} from '@apollo/client' // Mutations const ADD_NEW_AUTHOR = gql` mutation createAuthor($authorName:String, $description:String, $email:String) { createAuthor(author:{ authorName: $authorName, description: $description, email: $email }) { id authorName description email } } `; const UPDATE_AUTHOR = gql` mutation updateAuthor($id: String, $authorName:String, $description:String, $email:String) { updateAuthor(id:$id, author:{ authorName: $authorName, description: $description, email: $email }) { id authorName description email } } `; const DELETE_AUTHOR_BY_ID = gql` mutation deleteAuthor($id: String) { deleteAuthor(id: $id) } `; const DELETE_ALL_AUTHOR = gql` mutation deleteAllAuthor { deleteAllAuthors } `; export { GET_ALL_AUTHOR, GET_SINGLE_AUTHOR, ADD_NEW_AUTHOR, UPDATE_AUTHOR, DELETE_AUTHOR_BY_ID, DELETE_ALL_AUTHOR }
Configure Apollo client in App.js file
import React from 'react'; import { ApolloClient, createHttpLink, InMemoryCache, ApolloProvider} from '@apollo/client'; import RootNavigation from './src/RootNavigation'; //create http link based on base url const httpLink = createHttpLink({ uri: 'http://192.168.1.34:4000/graphql', }); //Create apollo client object const client = new ApolloClient({ link: httpLink , cache: new InMemoryCache(), // credentials:'include' }); export default function App() { return ( <ApolloProvider client={client}> <RootNavigation /> </ApolloProvider> ) }
- Explanation:
- In the above image “http://192.168.1.34” is the IP of my backend server PC & “4000” is port, “/graphql” is the default URL that is automatically added if you don’t specify in “apolloServer.applyMiddleware({})” “path” param ( It is part of backend )
await apolloServer.start(); await apolloServer.applyMiddleware({ app: app, path:"/graphql" })
- <ApolloProvider client={client}/>: That wraps our root component, Hence all child components or screens can access the “client”‘s instance & using that we can perform operations of fetch & update.
import React, { useState } from 'react' import { useMutation, useQuery, useApolloClient } from '@apollo/client'; import { View, Text, Flatlist, SafeAreaView, Alert, Image } from 'react-native' import { GET_ALL BOOKS }_from '../graphQLAPI/book'; export default function Home (props) { // local states const_[books, setBooks] = useState( []), // get apollo client instance const client = useApolloclient(); //fetch book data const { loading, error, data } = useQuery(GET_ALL_BOOKS), // delete book data const [deleteBook, { data: deletedData, loading: deleteLoading, error: deleteError }] = useMutation (DELETE_BOOK_BY_ID); return( <SafeAreaView style={{ flex: 1, backgroundColor: "#E8F3F3"}}> <FlatList data={data?.getAllBooks || []} // data.getAllBooks returns all book data renderItem={_renderItem} keyExtractor={(item, index) => index.toString() } refreshing={true} /> </SafeAreaView> ) }
- “useQuery()”: Above example fetch books data from backend using “useQuery()” hook.
- And “data.getAllBooks” contains all book data here “getAllBooks” is declared in /graphQLAPI/book.js
// Queries const GET_ALL_AUTHOR = gql` query getAllAuthors { getAllAuthors { id authorName description email } } `;
- “useMutation()” : This apollo client hook is used to perform insert, update, delete operations. The below image represents how that works
I hope the above code makes it clear to understand how we can insert data using the “useMutation” hook.
Conclusion
GraphQL makes it easy & efficient to fetch & update data. It can be integrated with your app easily. And also provides benefits of graphQL features.
At Bigscal Technologie, you can Hire React Native Developers & Offshore React Native Developers And Save Upto 60% On Costs And Time, With No Hiring Fees.
Hey just wanted to give you a quick heads up and let you know a
few of the images aren’t loading correctly. I’m not sure why but
I think its a linking issue. I’ve tried it in two different internet browsers and both show the same outcome.
Wow! After all I got a blog from where I be able to genuinely get useful data concerning my study and knowledge.
Hi mates, good paragraph and nice urging commented at this place, I am in fact enjoying by these.
Hi! I could have sworn I’ve been to this website before but after browsing
through some of the post I realized it’s new to me. Anyways,
I’m definitely happy I found it and I’ll be book-marking and
checking back frequently!
What’s up, yes this article is truly pleasant and I have learned
lot of things from it regarding blogging.
thanks.
Very nice write-up. I absolutely love this site. Stick with it!
Great blog here! Also your web site loads up fast!
What host are you using? Can I get your affiliate link
to your host? I wish my web site loaded up as quickly as yours lol
Hurrah! At last I got a weblog from where I be capable of genuinely take helpful facts regarding my study and knowledge.
Hi Dear, are you actually visiting this web page on a regular basis, if so then you
will without doubt obtain fastidious experience.
Howdy! This post could not be written any better! Reading
through this post reminds me of my good old room mate!
He always kept talking about this. I will forward this write-up to him.
Fairly certain he will have a good read. Many thanks for sharing!