Consuming Restful Data in a Vue application using Axios

Consuming Restful Data in a Vue application using Axios


In this article, you will learn how to Consume Restful Data in a Vue application using Axios by creating a simple Vue web application that keeps track of all the Corvid-19 cases around the world.

Our App will consume data from Microsoft API that will provide us with all the information we need about the Corvid-19 cases.

The client application is going to be built in Vue , as it is one of the most popular JavaScript frameworks out there.

In the course of this tutorial we will learn how to build user Interface in Vue,  Consuming APIs in Vue using Axios and, finally adding filters in a Vue application. 

You can Check out source code if you want to refer to it or take a peek as we get started.

Creating A New Vuejs Application

Let’s create a new directory corvid19-tracker and then move into that directory. This is where we will be creating our vue application.

cd desktop
mkdir corvid19-app && cd corvid19-app
vue create corvid-tracker

To run the vue app run the following codes on the terminal:

cd corvid-tracker
npm run serve

After compiling, it will be outputted on the terminal that the application is running on port http://localhost:8080/.

Note that the port number might differ on some local machines.

Accessing http://localhost:8080/  on our browser we will have this displayed:

Corvid-19 Cases Tracker App
Vue application

Install, setup UIkit and build the user interface.

Now that we have successfully created the vue application, lets install UIkit, a CSS Framework  into our application.

For this article we will use the node packager manager to install it into our application by running:

npm i uikit

After installing it we have to register it globally so that all the components in our application can use it.

To register it globally we need to import it in src/main.js file:

import uk from "uikit";
import Icons from "uikit/dist/js/uikit-icons";
uk.use(Icons);

By default UIkit uses less as a CSS preprocessor, So we need to install and configure less-loader. To do this open up the terminal and run this command: 

npm install -D less less-loader

After installing less and less-loader, we have to configure it by creating a webpack.config.js file in the root directory and then add the following code:

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        use: ["vue-style-loader", "css-loader", "less-loader"]
      }
    ]
  }
};

After doing this we can register UIkit CSS in our App.vue file by replacing the style with this:

<style lang="less">
@import "../node_modules/uikit/src/less/uikit.less";
</style>

With all that we just configure UI kit in our application.

N/b: Incase you arent comfortable with eslint in your application, you can deactivate it by creating a vue.config.js file in the root of our application and the add this:

module.exports = {
  chainWebpack: config => {
    config.module.rules.delete("eslint");
  }
};

This will delete all eslint rules from our application.

Now let clean up the User interface by changing the name of the file in our components folder from HelloWorld.vue to tracker.vue and then replace the code there with this:

<template>
  <div>
    <h3>Cases Tracker</h3>
  </div>
</template>
<script>
export default {};
</script>
<style scoped></style>

After doing this we will get an error on our browser. To fix that replace the code in views/Home.vue with this:

<template>
  <div>
    <tracker />
  </div>
</template>
<script>
import tracker from "@/components/tracker";
export default {
  components: {
    tracker
  }
};
</script>

And then replace the code in App.vue to this:

<template>
  <div id="app">
    <router-view />
  </div>
</template>
<script>
export default {};
</script>
<style lang="less">
@import "../node_modules/uikit/src/less/uikit.less";
</style>

Yea… with this we just cleaned up the codebase and now we can start creating our user interface for the application.

I created a simple user interface for the application,So modify the codes in tracker.vue with this:

<template>
  <div>
    <nav class="uk-background-secondary uk-light" uk-navbar>
      <div class="uk-navbar-left">
        <a class="uk-navbar-item uk-logo" href="#">Corvid-19 Cases Tracker</a>
      </div>
    </nav>
    <section>
      <div class="uk-container uk-margin-top">
        <div class="uk-child-width-1-4@s uk-grid-match" uk-grid>
          <div v-for="(data,key) in countries" :key="key">
            <div class="uk-card uk-card-default uk-card-hover uk-card-body">
              <div class="uk-card-badge uk-label">Badge</div>
              <h3 class="uk-card-title uk-margin-top">Name Of Country</h3>
              <ul class="uk-list uk-list-divider">
                <li>Total Confirmed:</li>
                <li>Total Deaths:</li>
                <li>Total Recovered:</li>
                <li>Last Updated:</li>
              </ul>
            </div>
          </div>
          <div></div>
        </div>
      </div>
    </section>
  </div>
</template>
<script>
export default {
  data() {
    return {
      countries: [
        { name: "jwev" },
        { name: "jwev" },
        { name: "jwev" },
        { name: "jwev" }
      ]
    };
  }
};
</script>
<style scoped></style>

What we just did was to create a simple card using the UI kit and then created an array called countries with dummy data. After doing that we looped over the array in the card section. Doing this will give us this:

Corvid-19 Cases Tracker App
card components

Now that we have a user interface for our application, we can now make a request to the Microsoft api to get the data.

To do this we need to define some states, mutations, and actions. Open up src/store/index.js and add a state called cases and then define a mutation that will mutate this state:

SET_CASES(state, payload) {
        state.cases = payload;
  },

It’s a good convention to use uppercase to name your mutations. The next thing to do is to define an action that will make the http request to the Microsoft API.

We need to install Axios which will help us handle all our http requests. So open up the console and type:

npm i axios --save

After installing it we need to bring it in so that vuex can use it to make the http request. So to do that add import Axios from 'Axios' after the vuex import on line 3.

Now its time to make the request. Define an action and call it getallCases and add the following code:

async getAllCases({ commit }) {
      try {
        let response = await axios.get("https://www.bing.com/covid/data");
        console.log(response);
        commit("SET_CASES",response.data.areas);
      } catch (err) {
        console.log(err);
      }
    }

Now we need to dispatch this action in our tracker.vue component. So to do that we need to, first of all, bring in the vuex state by importing it:

import { mapState } from "vuex";

Now to use the vuex state we will create a computed property:

computed: {
    ...mapState(["cases"])
  }

Now, let’s dispatch the getAllCases function that we defined in our vuex store. To add a method in the vue methods instance that will get the dispatched data:

async getResultFromVuex() {
      await this.$store.dispatch("getAllCases");
   }

Then add a created life cycle hook that will call this method when once this component is created:

created() {
    this.getResultFromVuex();
  },

After doing this open up your console and you see some browser restrictions on the console.

The browser is restricting us from having access to the Microsoft api, so we have to fix this.

We can actually create our backend service that will get this data and we configure the CORS issue directly in our backend service.

To do this create a server.js file in the root directory of our application and then add the following code:

const http = require("http");
const PORT = process.env.PORT || 4000;
const axios = require("axios");
let cases = async () => {
  try {
    let casesData = await axios.get("https://www.bing.com/covid/data");
    return casesData.data
  } catch (err) {
    console.log(err)
  }
}
const server = http.createServer(async (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/json',
    'Access-Control-Allow-Origin': '*',
    'X-Powered-By': 'nodejs'
  });
  let data = await cases();
  if (req.url === "/") {
    res.end(JSON.stringify(data));
  }
});
server.listen(PORT, () => {
  console.log(`App is listening to port ${PORT}`);
});

We, first of all, make an http request and then return the data that we get from that endpoint. We then create a route that will return the data.

Now we need to add a command in our package.json file that will run our backend server. Open up the package.json file and add this in the scripts section:

"start": "node server"

Now open up the terminal and run:

npm start

This will run our backend server on port 4000. After doing this open go to the browser and access localhost:4000 and we can see the data.

Now let modify the codes we wrote earlier in our vuex action. We will change the Axios URL from https://www.bing.com/covid/data to http://localhost:4000 And then modify the commit from commit("SET_CASES", response); to this commit("SET_CASES", response.data);

Lets open up another instance of our terminal and run our front end application and then go back to our console and we will see the returned data:

Corvid-19 Cases Tracker App
Returned data

We now have access to the data in our tracker component. To loop over the data we have to modify the loop and display the appropriate data needed. To modify the code in the tracker component to this:

<template>
  <div>
    <nav class="uk-background-secondary uk-light" uk-navbar>
      <div class="uk-navbar-left">
        <a class="uk-navbar-item uk-logo" href="#">Corvid-19 Cases Tracker</a>
      </div>
    </nav>
    <section>
      <div class="uk-container uk-margin-top">
        <div class="uk-child-width-1-4@s uk-grid-match" uk-grid>
          <div v-for="(data,key) in cases" :key="key">
            <div class="uk-card uk-card-default uk-card-hover uk-card-body">
              <div class="uk-card-badge uk-label">{{data.parentId}}</div>
              <h3 class="uk-card-title uk-margin-top">{{data.displayName}}</h3>
              <ul class="uk-list uk-list-divider">
                 <li>Total Confirmed:{{data.totalConfirmed || 0}}</li>
                <li>Total Deaths:{{data.totalDeaths || 0}}</li>
                <li>Total Recovered:{{data.totalRecovered ||0}}</li>
                <li>Last Updated:{{data.lastUpdated}}</li>
              </ul>
            </div>
          </div>
          <div></div>
        </div>
      </div>
    </section>
  </div>
</template>
<script>
import { mapState } from "vuex";
export default {
  methods: {
    async getResultFromVuex() {
      await this.$store.dispatch("getAllCases");
    }
  },
  created() {
    this.getResultFromVuex();
  },
  computed: {
    ...mapState(["cases"])
  }
};
</script>

And we will have the list of all the cases displayed:

cards with returned data

We are going to add a spinner so that the user will know when the data is loading. To do data we will define a new data property loading and set it to false:

loading:false

After that we change the getResultFromVuex method to this:

async getResultFromVuex() {
      this.loading = true;
      await this.$store.dispatch("getAllCases");
      this.loading = false;
    }

After doing this we can now set our spinner based on this condition. Now our template will look like this:

<template>
  <div>
    <nav class="uk-background-secondary uk-light" uk-navbar>
      <div class="uk-navbar-left">
        <a class="uk-navbar-item uk-logo" href="#">Corvid-19 Cases Tracker</a>
      </div>
    </nav>
    <section>
      <div class="uk-container uk-margin-top">
        <div>
          <div class="uk-background-secondary uk-margin-bottom uk-padding uk-panel">
            <div class="uk-margin">
              <input v-model="search" class="uk-input" type="text" placeholder="Filter By Country" />
            </div>
          </div>
        </div>
        <div v-if="loading" class="uk-align-center">
          <span uk-spinner="ratio: 4.5"></span>
        </div>
        <div v-else class="uk-child-width-1-4@s uk-grid-match" uk-grid>
          <div v-for="(data,key) in filteredCountries" :key="key">
            <div class="uk-card uk-card-default uk-card-hover uk-card-body">
              <div class="uk-card-badge uk-label">{{data.parentId}}</div>
              <h3 class="uk-card-title uk-margin-top">{{data.displayName}}</h3>
              <ul class="uk-list uk-list-divider">
                <li>Total Confirmed:{{data.totalConfirmed || 0}}</li>
                <li>Total Deaths:{{data.totalDeaths || 0}}</li>
                <li>Total Recovered:{{data.totalRecovered ||0}}</li>
                <li>Last Updated:{{moment(data.lastUpdated).format('MMMM Do YYYY, h:mm:ss a')}}</li>
              </ul>
            </div>
          </div>
          <div></div>
        </div>
      </div>
    </section>
  </div>
</template>

Another good thing we could do is to add a custom filter that will filter the list of countries based on what we input.

The reason for doing this is because the data is too much, so it will make us get any country data we are looking for easily.

Let continue by adding a search field above the cases list for filtering:

<div>
    <div class="uk-background-secondary uk-margin-bottom uk-padding uk-panel">
      <div class="uk-margin">
        <input class="uk-input" type="text" placeholder="Filter By Country" />
      </div>
    </div>
  </div>

Adding this code will give us this on our browser:

search bar

We will add a search instance in the data property and then bind it in the input field:

data() {
    return {
      search: ""
    };
  },

And bind it to the input field:

<input v-model="search" class="uk-input" type="text" placeholder="Filter By Country" />

Then we have to create a computed property that will handle this custom search. Modify the computed property in tracker.vue to this:

computed: {
    ...mapState(["cases"]),
    filteredCountries() {
      return this.cases.filter(country => {
        return country.displayName
          .toLowerCase()
          .match(this.search.toLowerCase());
      });
    }
  }

Here we define a computed filter filteredCountries and then we filter the cases array and then return the country that the display Name matches the inputted search value. Now we can replace the data loop from this:

v-for="(data,key) in cases" :key="key"

to

v-for="(data,key) in filteredCountries" :key="key"

With this, you can filter countries based on the display name.

Now we need to format the Last Updated that the data return. To do this we can use Momentjs.

To install Momentjs, open the terminal and type:

npm i moment --save

After installing it, we need to import it so that we can use it in the component. Open up the main.js file and add the following code

import moment from 'moment'
Vue.prototype.moment = moment

Now instead of displaying the last updated date in the raw form we can now use Moment to format it, So instead of  <li>Last Updated:{{data.lastUpdated}}</li> do this  <li>Last Updated:{{moment(data.lastUpdated).format('MMMM Do YYYY, h:mm:ss a')}}</li>

Now our date is properly formatted.

Conclusion

Congratulations,  you have just built a  Corvid-19 case tracker app using Vue that keeps track of all the Corvid-19 cases round the world.

We learned how to configure UIkit in a vuejs application, Solve CORS by using Nodejs to get the data and Finally, using our frontend to get the data from our custom backend.


Share on social media

//