Skip to content

12. Project [vuejs-10]: plugin [dao], asynchronous requests HTTP

The directory structure of the [vuejs-10] project is as follows:

Image

The [vuejs-10] project shows a component making a HTTP request to a remote server. The architecture used is as follows:

Image

A [Vue.js] component uses the [dao] layer to communicate with the tax calculation server.

12.1. Installing dependencies

The [vuejs-10] application uses the [axios] library to make asynchronous requests to the tax calculation server. We need to install this dependency:

Image

  • in [4-5], the line added to the [package.json] file after installing the [axios] library [1-3];

12.2. The [Dao] class

The [Dao] class is the one developed in section [La classe Dao]. We reproduce it here for reference:


'use strict';
 
// imports
import qs from 'qs'
 
// class [Dao]
class Dao {
 
  // manufacturer
  constructor(axios) {
    this.axios = axios;
    // session cookie
    this.sessionCookieName = "PHPSESSID";
    this.sessionCookie = '';
  }

  // init session
  async  initSession() {
    // query options HHTP [get /main.php?action=init-session&type=json]
    const options = {
      method: "GET",
      // URL parameters
      params: {
        action: 'init-session',
        type: 'json'
      }
    };
    // execute query HTTP
    return await this.getRemoteData(options);
  }
 
  async  authentifierUtilisateur(user, password) {
    // query options HHTP [post /main.php?action=authentifier-utilisateur]
    const options = {
      method: "POST",
      headers: {
        'Content-type': 'application/x-www-form-urlencoded',
      },
      // body of POST
      data: qs.stringify({
        user: user,
        password: password
      }),
      // URL parameters
      params: {
        action: 'authentifier-utilisateur'
      }
    };
    // execute query HTTP
    return await this.getRemoteData(options);
  }
 
  async getAdminData() {
    // query options HHTP [get /main.php?action=get-admindata]
    const options = {
      method: "GET",
      // URL parameters
      params: {
        action: 'get-admindata'
      }
    };
    // execute query HTTP
    const data = await this.getRemoteData(options);
    // result
    return data;
  }
 
  async  getRemoteData(options) {
    // for the session cookie
    if (!options.headers) {
      options.headers = {};
    }
    options.headers.Cookie = this.sessionCookie;
    // execute query HTTP
    let response;
    try {
      // asynchronous request
      response = await this.axios.request('main.php', options);
    } catch (error) {
      // the [error] parameter is an exception instance - it can take various forms
      if (error.response) {
        // the server response is in [error.response]
        response = error.response;
      } else {
        // error restart
        throw error;
      }
    }
    // response is the entire HTTP response from the server (HTTP headers + response itself)
    // retrieve the session cookie if it exists
    const setCookie = response.headers['set-cookie'];
    if (setCookie) {
      // setCookie is an array
      // look for the session cookie in this table
      let trouvé = false;
      let i = 0;
      while (!trouvé && i < setCookie.length) {
        // look for the session cookie
        const results = RegExp('^(' + this.sessionCookieName + '.+?);').exec(setCookie[i]);
        if (results) {
          // the session cookie is stored
          // eslint-disable-next-line require-atomic-updates
          this.sessionCookie = results[1];
          // we found
          trouvé = true;
        } else {
          // next item
          i++;
        }
      }
    }
    // the server response is in [response.data]
    return response.data;
  }
}
 
// class export
export default Dao;

The [vuejs-10] project uses only the asynchronous method [initSession] in lines 18–30. Note that the [Dao] class is instantiated with a [axios] parameter on line 10, which is initialized by the calling code. In this case, the calling code is the [./main.js] script.

12.3. The [pluginDao] plugin

The [pluginDao] plugin is as follows:


export default {
  install(Vue, dao) {
    // adds a [$dao] property to the Vue class
    Object.defineProperty(Vue.prototype, '$dao', {
      // when Vue.$dao is referenced, we return the 2nd parameter [dao]
      get: () => dao,
    })
  }
}

If we recall the explanation provided for the [event-bus] plugin, we can see that the [pluginDao] plugin creates a new property called [$dao] within the [Vue] class/function. This property will have (as remains to be shown) as its value the object exported by the [./Dao] script, i.e., the previous [Dao] class.

12.4. The main script [main.js]

The code for the main script [main.js] is as follows:


// imports
import Vue from 'vue'
import App from './App.vue'
import axios from 'axios';
 
// plugins
import BootstrapVue from 'bootstrap-vue'
Vue.use(BootstrapVue);
 
// bootstrap
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
 
// layer [dao]
import Dao from './Dao';
// axios configuration
axios.defaults.timeout = 2000;
axios.defaults.baseURL = 'http://localhost/php7/scripts-web/impots/version-14';
axios.defaults.withCredentials = true;
// instantiation layer [dao]
const dao = new Dao(axios);
 
// plugin [dao]
import pluginDao from './plugins/dao'
Vue.use(pluginDao, dao)
 
// configuration
Vue.config.productionTip = false
 
// instantiation project [App]
new Vue({
  render: h => h(App),
}).$mount('#app')

The script [main.js]:

  • instantiates the [dao] layer on lines 14–21;
  • integrates the [pluginDao] plugin on lines 24–25;
  • line 15: the [Dao] class is imported;
  • lines 17–18: the [axios] object is configured to execute the HTTP queries. This object is imported on line 4;
    • line 17: definition of a 2-second [timeout];
    • line 18: the URL for the tax calculation server;
    • line 19: to enable cookie exchange with the server;
  • lines 24–25: use of the [pluginDao] plugin
    • line 24: import the plugin;
    • Line 25: Plugin integration. Note that the second parameter of the [Vue.use] method is the reference to the [dao] layer defined on line 21. This is why the property [Vue.$dao] will refer to the layer [dao] in all instances of the class/function [Vue], i.e., in all components [Vue.js];

12.5. The main view [App.vue]

The code for the main view [App] is as follows:


<template>
  <div class="container">
    <b-card>
      <!-- message -->
      <b-alert show variant="success" align="center">
        <h4>[vuejs-10] : plugin [dao], requêtes HTTP asynchrones</h4>
      </b-alert>
      <!-- component making an asynchronous request to the tax calculation server-->
      <Component1 @error="doSomethingWithError" @endWaiting="endWaiting" @beginWaiting="beginWaiting" />
      <!-- error display -->
      <b-alert show
               variant="danger"
               v-if="showError">Evénement [error] intercepté par [App]. Valeur reçue = {{error}}</b-alert>
      <!-- message waiting with a spinner -->
      <b-alert show v-if="showWaiting" variant="light">
        <strong>Requête au serveur de calcul d'impôt en cours...</strong>
        <b-spinner variant="primary" label="Spinning"></b-spinner>
      </b-alert>
    </b-card>
  </div>
</template>
 
<script>
  import Component1 from "./components/Component1";
  export default {
    name: "app",
    // component status
    data() {
      return {
        // controls the waiting spinner
        showWaiting: false,
        // controls error display
        showError: false,
        // intercepted error
        error: {}
      };
    },
    // components used
    components: {
      Component1
    },
    // event management methods
    methods: {
      // start waiting
      beginWaiting() {
        // wait is displayed
        this.showWaiting = true;
        // hide error msg
        this.showError = false;
      },
      // end waiting
      endWaiting() {
        // we hide the wait
        this.showWaiting = false;
      },
      // error handling
      doSomethingWithError(error) {
        // we note that there has been an error
        this.error = error;
        // error msg is displayed
        this.showError = true;
      }
    }
  };
</script>

Comments

  • Line 9: [Component1] is the component that makes the asynchronous HTTP request. It can emit three events:
    • [beginWaiting]: The request is about to be made. A loading message must be displayed to the user;
    • [endWaiting]: The request is complete. The wait must be terminated;
    • [error]: The request failed. An error message must be displayed;
  • lines 10–13: the alert that displays any error message. It is controlled by the Boolean [showError] on line 33. It displays the error on line 35;
  • lines 14–18: the alert that displays the loading message with a spinner. It is controlled by the Boolean [showWaiting] on line 47;
  • lines 45–50: [beginWaiting] is the method executed upon receipt of the [beginWaiting] event. It displays the loading message (line 47) and hides the error message (line 49) in case it is visible following a previous operation;
  • lines 52–55: [endWaiting] is the method executed upon receipt of the [endWaiting] event. It hides the waiting message (line 54);
  • lines 57–62: [doSomethingWithError] is the method executed upon receipt of the [error] event. It logs the received error (line 59) and displays the error message (line 61);

12.6. The [Component1] component

The code for the [Component1] component is as follows:


<template>
  <b-row>
    <b-col>
      <b-alert show
               variant="warning"
               v-if="showMsg">Valeur reçue du serveur = {{data}}</b-alert>
    </b-col>
  </b-row>
</template>
 
<script>
  export default {
    name: "component1",
    // component status
    data() {
      return {
        showMsg: false
      };
    },
    // event management methods
    methods: {
      // processing data received from the server
      doSomethingWithData(data) {
        // record the data received
        this.data = data;
        // we display it
        this.showMsg = true;
      }
    },
    // the component has just been created
    created() {
      // on initialise la session avec le serveur - requête asynchrone
      // we use the promise rendered by [dao] layer methods
      // we signal the start of the operation
      this.$emit("beginWaiting");
      // launch asynchronous operation
      this.$dao
        // initialize a jSON session with the tax calculation server
        .initSession()
        // method that processes the data received in the event of success
        .then(data => {
          // we process the data received
          this.doSomethingWithData(data);
        })
        // error handling method in case of error
        .catch(error => {
          // trace the error back to the parent component
          this.$emit("error", error.message);
        }).finally(() => {
          // end of wait
          this.$emit("endWaiting");
        })
    }
  };
</script>

Comments

  • lines 4-6: the component consists of a single alert that displays the value returned by the tax calculation server, but only if the HTTP query is successful. This alert is controlled by the Boolean [showMsg] on line 17;
  • lines 31–53: The HTTP request is made as soon as the component is created. Its code is therefore placed in the [created] method on line 31;
  • line 35: the parent component is notified that the asynchronous request is about to start;
  • lines 37–39: the [this.$dao.initSession] method is executed. It initializes a jSON session with the tax calculation server. The immediate result of this method is a [Promise];
  • lines 41–44: this code executes when the server has returned its result without an error. The server’s result is in [data]. On line 43, the [doSomethingWithData] method is called to process this result;
  • lines 46–49: this code runs if an error occurs while executing the request. On line 48, the parent component is notified that an error has occurred, and the error message [error.message] is passed to it;
  • lines 49–52: this code runs in all cases. The parent component is notified that the HTTP query has completed;
  • Lines 23–28: The method [doSomethingWithData] is responsible for processing the data [data] sent by the server. On line 25, this data is stored, and on line 27, it is displayed;

12.7. Running the project

Image

If the tax calculation server is not running when the project is launched, the following result is obtained:

Image

Let’s launch the [Laragon] server (see https://tahe.developpez.com/tutoriels-cours/php7) and reload the page above. The result is then as follows:

Image

Note: Here we are using version 14 from the tax calculation server defined at https://tahe.developpez.com/tutoriels-cours/php7.