Vue.js and Flask, Axios and RESTful API

Vue.js and Flask, Axios and RESTful API

Web UI to control an embedded system

·

2 min read

I really don't know how to name this post. So I just simply listed all the technologies that involved.

The requirement goes like this: Displaying and modifying some JSON files on an embedded device using Vue.js and RESTful API.

Flask-RESTPlus

Flask-RESTPlus is a very helpful extension if you want to describe your API and expose its documentation properly with Flask. It's not too hard to use. But I want to not only generate the API documentation but also serve the Vue.js web pages. I did some research and got this:

from flask import Flask, render_template, make_response
from flask_restplus import Resource, Api

app = Flask(__name__)

api = Api(app,
          version='1.0',
          title= 'title'
          description= 'desc'
          doc='/apis')

@api.route('/app')
class AppIndex(Resource):
    def get(self):
        headers = {'Content-Type': 'text/html'}
        return make_response(render_template('index.html'), 200, headers)

...

if __name__ == '__main__':
    app.run(debug=True)

The get() function in AppIndex class does the trick.

Vue.js

I've never used Vue.js before. Vue actually doesn't have a HTTP client built in. They say they had, but got rid of it eventually to keep the core compact. I kind of agree with that idea. So now Axios is used to handle the HTTP methods. There are some tricks.

Multiple requests

// Other imports...
import axios from "axios";

export default {
    data() {
        return {
            // ...
        };
    },
    components: {
        // ...
    },
    computed: {
        // ...
    },
    methods: {
        // ...
    },
    mounted() {
        const requestOne = axios.get("http://127.0.0.1:5000/json_file");
        const requestTwo = axios.get("http://127.0.0.1:5000/json_data");
        axios
            .all([requestOne, requestTwo])
            .then(
                axios.spread((...responses) => {
                    this.$store.dispatch(
                        "updateJsonFileAction",
                        responses[0].data
                    );
                    this.$store.dispatch(
                        "updateJsonDataAction",
                        responses[1].data
                    );
                })
            )
            .catch(errors => {
                alert(errors);
            });
    }
};

Cross Origin Resource Sharing

But actually the above API call will fail if we just leave the whole thing like that. It would report an "Network error". After some research I found that was because the Flask server only accepts the requests from the same port number (5000). To fix this, I had to install Flask-CORS, an extension for handling Cross Origin Resource Sharing (CORS), making cross-origin AJAX possible. It's easy to use:

# ...

from flask_cors import CORS

app = Flask(__name__)
cors = CORS(app)

# ...

Deployment

To make the Vue.js project getting built for Flask template, we can add/edit the following three entries:

vue.config.js

    // ...
    publicPath: '',
    assetsDir: '../static',
    baseUrl: '',

And another one is Output directory. If we open up a Vue UI, it's in Parameters dialog box in build task. We set this parameter to templates.

Then after "build", we can directly copy the generated templates and static folders into Flask directory.