Author avatar

Gaurav Singhal

Get a JSON of a Mongo Collection with an XHR Request in React

Gaurav Singhal

  • Oct 2, 2020
  • 7 Min read
  • 60 Views
  • Oct 2, 2020
  • 7 Min read
  • 60 Views
Web Development
Front End Web Development
Client-side Frameworks
React

Introduction

When you are working in a MERN (MongoDB, Express, React, and Node) stack app, you are often required to fetch a JSON of a Mongo collection and use that data on the frontend. With the popularity of NoSQL databases, it's really simple to fetch data from a Mongo collection via a React app through an express server.

This guide walks you through the essentials of making an XHR request to an endpoint on an express server to get JSON of a Mongo collection in your MongoDB database.

Setting up the Backend

If you already have an express server with an endpoint where you can fetch your Mongo collection, you can skip this step. If you don't, you can easily set up an express server using NodeJS using the following steps.

First, create a new npm project using the following command:

1
npm init -y 
shell

Install mongoose, body-parser, and express.

1
npm i mongoose express body-parser 
shell

Creating a Schema

Create a schema called todoSchema for your Mongo collection and a model called Todo, as shown below, and export it using module.exports.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const mongoose=require('mongoose'); 
 
const todoSchema=mongoose.Schema({ 
 name:{ 
 type:String, 
 required:true 
 }, 
 status:{ 
 type:String, 
 required:true 
 } 
},{timestamps:true}) 
 
const Todo=mongoose.model('Todo',todoSchema); 
module.exports=Todo; 
javascript

Creating a Controller

Create a controller for fetching all the to-do's from your Mongo collection using the find() method on your model and export it at the end.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const Todo=require('./../models/Todo'); 
 
 
const getTodos=(req,res)=>{ 
 
 Todo.find() 
 .then(result=>{ 
 console.log('result: ',result) 
 res.send(result.length>0?result:'No Todos'); 
 }) 
 .catch(err=>{ 
 console.log(err); 
 }) 
} 
 
module.exports={ 
 getTodos 
} 
javascript

Setting up an Express Router

Create a router instance of the express by invoking the Router() method on it. Next, create a route that will act as an API endpoint to get all the to-do's from your Mongo collection by calling the get() method and passing the route as the first parameter and your controller function as the second parameter.

1
2
3
4
5
6
const express=require('express'); 
const todoController=require('./controllers/todoConroller'); 
 
const router=express.Router(); 
 
module.exports=router.get('/todos',todoController.getTodos); 
javascript

Finally, put it all together by creating an express app and connecting your MongoDB database. This example uses MongoDB Atlas to create and connect to the cloud database using a dbURI string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const express=require('express'); 
const mongoose=require('mongoose'); 
const bodyParser=require('body-parser'); 
const routes=require('./routes'); 
 
const PORT=5000; 
 
const dbURI=<Add your MongoDB atlas dbURI here> 
 
const app=express(); 
 
mongoose.connect(dbURI,{useNewUrlParser:true,useUnifiedTopology:true}) 
 .then(()=>{ 
 app.listen(PORT,(req,res)=>{ 
 console.log(`connected to db`); 
 }) 
 }) 
 .catch(err=>{ 
 console.log(err); 
 }) 
 
 
app.use(bodyParser.json()) 
app.use(routes) 
 
javascript

You can now access your mongo collection using the endpoint http://localhost:5000/todos after running the node app in the terminal.

Creating the Frontend

The Mongo collection you will consume looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[ 
 { 
 "_id": "5f709a7fe510821d48eaf3cc", 
 "name": "Paint a picture", 
 "status": "Incomplete", 
 "createdAt": "2020-09-27T13:58:23.023Z", 
 "updatedAt": "2020-09-27T14:01:32.580Z", 
 "__v": 0 
 }, 
 { 
 "_id": "5f71dcf907cf490004e07d80", 
 "name": "Walk the Dog", 
 "status": "Incomplete", 
 "createdAt": "2020-09-28T12:54:17.877Z", 
 "updatedAt": "2020-09-28T12:54:17.877Z", 
 "__v": 0 
 }, 
 { 
 "_id": "5f71dd1207cf490004e07d81", 
 "name": "Cook Dinner", 
 "status": "In Progress", 
 "createdAt": "2020-09-28T12:54:42.340Z", 
 "updatedAt": "2020-09-28T12:54:42.340Z", 
 "__v": 0 
 } 
] 
json

This JSON collection is returned from the endpoint created in the previous section after adding data manually to the database. If you want to use your collection, use the API created in the previous section or use the above collection inside a local text file as an API mockup. The method of making XHR requests in all three cases is the same.

Making an XHR Request

Inside your React app, import useState and useEffect. The useState hook is used to create a state where the JSON object from the endpoint is stored. Make an XHR request inside the useEffect lifecycle hook's callback function using the XMLHttpRequest object. Have a look at the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import React,{useState, useEffect} from 'react'; 
import './App.css'; 
 
function App() { 
 const [todos,setTodos]=useState() 
 useEffect(()=>{ 
 var request = new XMLHttpRequest(); 
 request.onreadystatechange = function() { 
 if (request.readyState == 4 && request.status == 200) { 
 const response=JSON.parse(request.response) 
 setTodos(response) 
 } 
 }; 
 request.open('GET', 'http://localhost:5000/todos', true); 
 request.send(); 
 },[]) 
 
 useEffect(()=>{ 
 console.log(todos) 
 },[todos]) 
 return ( 
 <div className="App"> 
 </div> 
 ); 
} 
 
export default App; 
 
jsx

Inside the useEffect()'s callback function, create a new instance of the XMLHttpRequest object. Then call the endpoint with the request method type (which is GET in this example) to create a gateway to that request. This step is essential as it tells the browser that you are now open for making requests to an endpoint to get some resources back. By calling the send() method, you invoke the function fired by the onreadystatechange event inside which you check the readyState and status of the request. The readyState 4 indicates that the request is ready to be processed and status 200 is received from the endpoint, indicating everything is okay. Inside the if block, parse the response object from the request to a JSON to get the JSON of your Mongo collection and assign it to your state variable. This is how you make an XHR request to get JSON of your Mongo collection and store it inside a local state of your component. As a final step, you can render this collection's details on the DOM by looping through the state.

1
2
3
4
5
 ... 
 <div className="App"> 
 {todos && todos.map(todo=><p>{todo.name}</p>)} 
 </div> 
 ... 
jsx

Now you can see the to-do's from your Mongo collection on the page.

Conclusion

Although making XHR requests is the most primitive method of making AJAX requests, you should always go for modern approaches like the fetch API or Axios to make API calls. They are easy to use, have a shallow learning curve, and can handle multiple and bulky requests using advanced features such as promise chaining. The same example used in this guide can be coded in a cleaner manner using Axios or Fetch API. Try that out as an exercise.

2