Axios HTTP Client with React JS - BOOKC -->

Axios HTTP Client with React JS

Saturday, November 3, 2018


Hi guys! Are you a fan on React JS? Not yet? I invite you to become a React fan! This is a very interesting JS library to work with. Since React JS is for managing front-end of web applications, it needs a back-end written in any language to handle data. It can be Node JS/ Spring Boot/ .NET/ PHP or any other technology. So, in this article, I will use a Spring Boot REST API to call and manage data with GET/POST request.

Now we need a way to connect a back-end and send requests. What will be the solution in React? Most recommended way is using Axios Http Client.
I'll explain the way to use it.

Prerequisites:
  • Java should be installed in your machine.
  • Node JS and React should be installed in your machine.

Let's Start!

First we need a fresh React JS project. So create a project using the below command.
create-react-app axios-app

Get the Spring Boot project and run it using Intellij IDEA. It will be started on port 8080. Now our API routes are ready! These are the routes..

http://localhost:8080/users/
http://localhost:8080/users/{id}
http://localhost:8080/users/add
http://localhost:8080/users/delete/{id}

Now we can start implementing front end with React JS. Open the React project in a text editor. As I said before, we need Axios to be installed into the project. So type the below command on a terminal.
npm install axios --save

We are ready to import axios to the application! Open App.js file. Since this is an example project, all the things I do is related with App.js component only.

You can see the basic component structure in this file. Now I'm going to modify the content. First I will explain it. This is the UI of the application.

All the actions are performed using button clicks with GET and POST requests. So we need 4 methods. Among them, 2 actions for form submissions and the other 2 for clicks.  We have to trigger some inputs. So we need input triggering methods also. We need 4 of them. Then when we perform addition and deletion, we need a form to be submitted. First we define a constructor to declare the state of the component and the method bindings.

Code version 1 of our App.js is shown here. All the definitions and method usages are included in this one.

App.js - version 1

import React, { Component } from 'react';
import './App.css';
import axios from 'axios';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      users: [], 
      user: [],
      name: "",
      age: 0,
      job: "",
      addMsg: "",
      deleteMsg: ""
    }
    this.handleNameChange = this.handleNameChange.bind(this);
    this.handleAgeChange = this.handleAgeChange.bind(this);
    this.handleJobChange = this.handleJobChange.bind(this);
    this.handleIdChange = this.handleIdChange.bind(this);
    this.addUser = this.addUser.bind(this);
    this.deleteUser = this.deleteUser.bind(this);
    this.getUsers = this.getUsers.bind(this);
    this.getSingleUser = this.getSingleUser.bind(this);
  }

  handleNameChange(event) {

  }

  handleJobChange(event) {

  }

  handleAgeChange(event) {

  }

  handleIdChange(event) {

  }

  getUsers() {
    
  }

  getSingleUser() {

  }

  addUser(event) {
 
  }

  deleteUser(event) {

  }

  render() {
    return (
      <div className="App">
        <nav className="navbar navbar-expand-lg navbar-dark bg-dark">
          <a className="navbar-brand" href="/">AXIOS HTTP CLIENT</a>
          <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span className="navbar-toggler-icon"></span>
          </button>
        </nav>
        <div className="container" style={{marginTop: '50px'}}>
          <div className="card">
            <div className="card-body">
              <h4 className="text-left">GET REQUEST</h4><hr/>
              <div className="input-group mb-3">
                <input type="text" className="form-control" disabled placeholder="http://localhost:8080/users/"/>
                <span>
                  <button className="btn btn-success" onClick={this.getUsers}>GET USERS</button>
                </span>
              </div>
              <div className="row">
              <table className="table table-bordered table-striped" style={{marginRight: '15px', marginLeft: '15px'}}>
                <thead>
                  <tr>
                    <th width="25%">ID</th>
                    <th width="25%">Name</th>
                    <th width="25%">Age</th>
                    <th width="25%">Job</th>
                  </tr>
                </thead>
                <tbody>

                </tbody>
              </table>  
              </div>              
              <br/>
              <h4 className="text-left">GET SINGLE REQUEST</h4><hr/>
              <div className="input-group mb-3">
              <input type="text" className="form-control" disabled placeholder="http://localhost:8080/users/{id}"/>
              <input type="text" className="form-control" name="id" onChange={this.handleIdChange} placeholder="User ID"/>
                <span>
                  <button className="btn btn-warning" onClick={this.getSingleUser}>GET USER</button>
                </span>
              </div>
              <div className="row">
              <table className="table table-bordered table-striped" style={{marginRight: '15px', marginLeft: '15px'}}>
                <thead>
                  <tr>
                    <th width="25%">ID</th>
                    <th width="25%">Name</th>
                    <th width="25%">Age</th>
                    <th width="25%">Job</th>
                  </tr>
                </thead>
                <tbody>
                   
                </tbody>
              </table>  
              </div>              
              <br/>
              <h4 className="text-left">POST REQUEST</h4><hr/>
              <input type="text" className="form-control" disabled placeholder="http://localhost:8080/users/add"/>
              <br/>
              <form onSubmit={this.addUser}>
                <div className="form-row">
                  <div className="col-md-3 mb-3">
                    <input type="text" className="form-control" name="name" onChange={this.handleNameChange} placeholder="Username"/>
                  </div>
                  <div className="col-md-3 mb-3">
                    <input type="text" className="form-control" name="job" onChange={this.handleJobChange} placeholder="Job"/>
                  </div>
                  <div className="col-md-3 mb-3">
                    <input type="text" className="form-control" name="age" onChange={this.handleAgeChange} placeholder="Age"/>
                  </div>                 
                  <span>
                    <button className="btn btn-primary" style={{marginTop: '0px'}}>ADD USER</button>
                  </span>                 
                </div>               
              </form>
              <p style={{color: 'green'}}>{this.state.addMsg}</p>
              <br/>
              <h4 className="text-left">DELETE REQUEST</h4><hr/>
              <input type="text" className="form-control" disabled placeholder="http://localhost:8080/users/delete/{id}"/>
              <br/>
              <form onSubmit={this.deleteUser}>
                <div className="form-row">
                  <div className="col-md-3 mb-3">
                    <input type="text" className="form-control" name="id" onChange={this.handleIdChange} placeholder="User ID"/>
                  </div>            
                  <span>
                    <button className="btn btn-danger" style={{marginTop: '0px'}}>DELETE USER</button>
                  </span>                 
                </div>               
              </form>
              <p style={{color: 'red'}}>{this.state.deleteMsg}</p>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default App;

I have imported axios but still it is not used. This is the import line...
import axios from 'axios';

All the states are defined in the constructor. What are they?

users array - To store all the users
user array - To store one user
id, name, age - Input fields
addMsg, deleteMsg - Error and success messages

All the methods are bound within the constructor. This is my preferred way. You can user arrow functions with inline binding also! Here, the methods starting with the handle word phrase are for handling states of the input fields. There are two messages. Among them, addMsg is to display success message after adding a new user. And deleteMsg to display an alert after deleting a user.

There are two forms. In these forms we perform onSubmit actions. An the first two buttons are just clicks. They perform onClick actions. They are included in the code at the correct places. Look at the code carefully.
Now we have to implement the state triggering methods first.

Handling state

  handleNameChange(event) {
    this.setState({name: event.target.value});
  }

  handleJobChange(event) {
    this.setState({job: event.target.value});
  }

  handleAgeChange(event) {
    this.setState({age: event.target.value});
  }

  handleIdChange(event) {
    this.setState({id: event.target.value});
  }

Now our states are also ready to be handled. So this is the time to use AXIOS!
We imported it as axios. Therefore we can use it as axios.get(), axios.post()...

Connecting with DB

We have to connect to a Mongo database. This database is used in my Spring Boot project. If you have not followed that article, visit it from here...

You can just create a new MongoDB called api and then create a new collection called users in it. Then insert some documents using a MongoDB client like RoboMongo/Compass or your Teminal. This is the format of a user object.

{
"name" : "Daniel",
"job" : "SE",
"age" : 27
}

AXIOS GET REQUESTS

Now we have some documents in the users collection. Axios has been imported to the project also. I will bind this request to the method defined as getUsers. So, how to perform a GET Request?

  getUsers() {
    axios.get('http://localhost:8080/users/')
    .then((res) => {
      console.log(res.data);
      this.setState({users: res.data})
    })
    .catch((err) => {
      console.log(err);
    })
  }

First we do a GET request call to our Spring Boot API root implemented for fetching all users. When the GET request is called correctly, we get a response. It is stored in the variable called res, here.  This res object have a lot of details. Among them, there's a key called data, inside this res object. That key's values are the actual data coming from database. That's why we set res.data to the users array. You can see a console.log of res.data. It is to confirm the data fetching process, before displaying data. Then we set the results into the array called usersdefined in the state object.

Now you can click on GET USERS button and see the result on browser console. Now you have the users stored in users array. Next part is displaying the results. Only thing you have to do is to map the results and loop through in the array. Go to the section called <tbody></tbody> and place this code. (First table you meet in the code)

                  {this.state.users.map((user,i) => {
                    return (                      
                      <tr key={i}>
                        <td>{user.id}</td>
                        <td>{user.name}</td>
                        <td>{user.age}</td>
                        <td>{user.job}</td>
                      </tr>                     
                    )
                  })}
Now you can fetch all the users with a button click! Let's move to send a GET Request to fetch a provided user by ID.
My method for this is, getSingleUser. This method body is differenet. You can see, in our UI there's a input field to enter ID in this scenario. Got it? So there we have to enter ID. Then this ID is set by the state and passed as a parameter to the GET Request. Look at the code below.

  getSingleUser() {
    axios.get(`http://localhost:8080/users/${this.state.id}`)
    .then((res) => {
      console.log(res.data);
      this.setState({user: res.data})
    })
    .catch((err) => {
      console.log(err);
    })
  }

As we did before, res.data; the segment with fetched data is set to the array called user, defined in the state object. Then we can print it to the body in this way. Go to the second table and place this code within  <tbody></tbody> section.

                  <tr>
                    <td>{this.state.user.id}</td>
                    <td>{this.state.user.name}</td>
                    <td>{this.state.user.age}</td>
                    <td>{this.state.user.job}</td>
                  </tr>                   

When you enter an existing ID of a user and click on GET USER button, you will receive the user with the provided ID.

AXIOS POST REQUESTS

Usually POST request are submitting some data to the server and get a response. In my example also, scenario will be the same. I'm going to insert a user into the Mongo database collection - users.
You can see a form with 3 input fields in our UI. This is the place we perform our POST request. Let's implement the method. My method used for this scenario is addUser.

  addUser(event) {
    event.preventDefault();

    const user = {
      name: this.state.name,
      job: this.state.job,
      age: this.state.age
    };

    axios.post('http://localhost:8080/users/add', user)
    .then(res => {
      console.log(res.data);
      this.setState({addMsg: "User is successfully added to the database"})
    })
    .catch((err) => {
      console.log(err);
    })
  }

This is somewhat different than a GET request. First I have defined an user object. This contains 3 key value pairs. The keys are name, job and age. Then we call to the AP URL in our Spring Boot application. But remember to pass the defined user object as a parameter. After adding user, something should be printed on the screen to confirm the addition. So I have set the state of addMsg as meaningful message. This message is printed by the line included like this, in the UI.
<p style={{color: 'green'}}>{this.state.addMsg}</p>

When you enter the details and click on ADD USER button, the data will be saved to the database and a success message will be displayed!

Always console.log the response to see whether the expected result is coming or not.

AXIOS DELETE REQUESTS

Normally a delete request is also working as a post request. But when we use request type as delete, we don't have to explicitly say this is a delete request. It knows the way to recognize a delete request. To demonstrate this request, I have designed a form like the above adding scenario. We have to give the ID of the user to be deleted. When click on delete button, it will delete the user from our database.
I use deleteUser method defined before to submit the form. Let's implement the method body.

  deleteUser(event) {
    event.preventDefault();

    axios.delete(`http://localhost:8080/users/delete/${this.state.id}`)
    .then(res => {
      console.log(res.data);
      this.setState({deleteMsg: "User is successfully deleted from database"})
    })
    .catch((err) => {
      console.log(err);
    })
  }

User ID is passed as a parameter to find the relevant user. After the deletion has been done, there should be a message to inform us. So, I changed the state of deleteMsg as a meaningful way.

Now our task is completed! 

I have included the fully completed App.js component here.


We have come to the end of this article. I think you have gained some knowledge to handle data with Axios when you work with React JS. Try to create some applications to test this! As a new comer, that is the thing I do to increase my knowledge.

I will write more on React JS in future!

Good Bye Guys!