なぽろぐ

気ままに感じたことを記事にまとめます。

Vue.jsをFlaskで動かす

Vue.jsをFlaskで動かしたい

VueとFlaskの連携について説明します.flask_restfulを用いて簡単な通信もやります.

Vueのプロジェクトを作る

vue init webpack test

いろいろ聞かれますが,だいたいEnterで大丈夫です.ESLintだけは使い方がよくわかってないのでNoにしてます. f:id:Naporitan:20190210224121p:plain

まってるとめっちゃインストーーーーーーーールって感じになるので放置です.結構長い時間がかかるかも

インストールが終わったら以下のコマンドでプロジェクトに入っておいてください

cd test

あとで使うのでインストールしておくといいかも・・・

npm install axios --save 
npm install url-join --save

Flaskをインストール

先ほどtestディレクトリに入ったのでそのまま

mkdir env
python3 -m venv env
source env/bin/activate

pip3 install flask flask_cors flask_restful

これでとりあえずFlaskを使える環境は整いました

Flaskでサーバーを立てる

次にFlaskでwebサーバーを立てます

そのまえにVueのプロジェクトをビルドして・・・・

npm run build

ビルドしている間にバックエンドの方やっちゃいましょう!

ファイル名はserver.pyで

配置する場所はプロジェクトフォルダ直下(index.htmlとか.gitignoreある場所)

from flask import Flask, jsonify, render_template
from flask_cors import CORS
from flask_restful import Api, Resource, reqparse

app = Flask(__name__, static_folder="dist/static", template_folder="dist")
CORS(app)
api = Api(app)

#get, post, put, deleteリクエストがあったときの処理をそれぞれ書く
class test(Resource):
    parser = reqparse.RequestParser()
    # add_argumentでパラメータを取得できます
    # この辺はflask_restfulの公式ドキュメントに色々乗ってるのでそっち見た方がよさげ
    parser.add_argument("message")

    def get(self):
        args = self.parser.parse_args()
        return {"message": args["message"]}

    def post(self):
        args = self.parser.parse_args()
        return {"message": args["message"]}

    def put(self):
        args = self.parser.parse_args()
        return {"message": args["message"]}

    def delete(self):
        args = self.parser.parse_args()
        return {"message": args["message"]}


api.add_resource(test, "/api/test")


@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def get_vue(path):
    return render_template('index.html')

# 一応エラーハンドラ


@app.errorhandler(403)
@app.errorhandler(404)
@app.errorhandler(500)
def error_handler(error):
    msg = 'Error: {code}'.format(code=error.code)
    return jsonify({"result": "Failed",
                    "message": msg,
                    "errorcode": error.code})


if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)
python3 server.py

これでlocalhost:5000につないだときにVueの画面が出てこれば成功です

server.jsも全く同じことしてるんだから早めに気づけばよかった・・・って思ってます

API叩きたくない?叩きたいよね

先ほど作ったserver.pyにAPIが生えているのでちょっと通信してみましょう

いちいちビルド(npm run build)していると面倒なので開発版でもserver.pyに接続できるようにします.

と言っても,npm run devで立つサーバーとserver.pyで立てるサーバで2つあるからserver.pyの方に誘導してあげるだけですが・・・・

APIと通信するモジュール(myAxios.js)

import axios from 'axios'
const urljoin = require('url-join');
const debug = process.env.NODE_ENV != 'production'
const debug_url = "http://localhost:5000"

const onSuccess = (res) => {
    if (debug) console.log(' << ' + JSON.stringify(res.data))
    return Promise.resolve(res)
}

const onError = (res) => {
    console.log(res)
    throw new Error('API error')
}

const accessUrl = (endpoint) => {
    if (debug) return urljoin(debug_url, endpoint)
    else return endpoint
}

const debugMessage = (type, url, params) => {
    console.log(type + ": " + url + '\nparams: ' + JSON.stringify(params))
}

export default {
    get: (url, params) => {
        let reqUrl = accessUrl(url)
        if (debug) debugMessage("GET", reqUrl, params)
        return axios.get(reqUrl, {
            params
        }).then(onSuccess).catch(onError)
    },
    post: (url, params) => {
        let reqUrl = accessUrl(url)
        if (debug) debugMessage("POST", reqUrl, params)
        return axios.post(reqUrl, params).then(onSuccess).catch(onError)
    },
    put: (url, params) => {
        let reqUrl = accessUrl(url)
        if (debug) debugMessage("PUT", reqUrl, params)
        return axios.put(reqUrl, params).then(onSuccess).catch(onError)
    },
    delete: (url, params) => {
        let reqUrl = accessUrl(url)
        if (debug) debugMessage("DELTE", reqUrl, params)
        return axios.delete(reqUrl, {
            data: params
        }).then(onSuccess).catch(onError)
    }
}
const debug_url = "http://localhost:5000"

となっているのはserver.pyがポート5000で立つからです.server.pyの立つポート別の時はそれを指定してあげてください

test.vueをcomponentsの中に作ってください.内容はこんな感じ

<template>
  <h1>
    {{get}}
    {{post}}
    {{put}}
    {{del}}
  </h1>
</template>

<script>
import myAxios from "./myAxios.js";
export default {
  name: "ApiTest",
  data() {
    return {
      get: "",
      post: "",
      put: "",
      del: ""
    };
  },
  created() {
    myAxios.get("api/test", { message: "Hello" }).then(res => {
      this.get = res.data.message;
    });
    myAxios.post("api/test", { message: "World" }).then(res => {
      this.post = res.data.message;
    });
    myAxios.put("api/test", { message: "Vueと" }).then(res => {
      this.put = res.data.message;
    });
    myAxios.delete("api/test", { message: "Flaskの連携" }).then(res => {
      this.del = res.data.message;
    });
  }
};
</script>

このままだとHelloWorld.vueしか表示されないのでちょっと変えます.

router/index.jsを以下のように変更

import Vue from 'vue'
import Router from 'vue-router'
import test from '@/components/test'

Vue.use(Router)

export default new Router({
    mode: 'history',
    routes: [{
        path: '/',
        name: 'Test',
        component: test
    }]
})

npm run devしてhttp://localhost:8080に接続すると・・・ f:id:Naporitan:20190210223952p:plain できましたね!

もちろん

npm run build

をしてhttp://localhost:5000に接続しても同じ画面になると思います.

終わりに

FlaskとVueの連携を説明してみました. めっちゃむずかしそーって思ってたんですけど案外簡単ですね!これでめんどくさそうなDB処理はPythonでかけそうです

というかVueRouterでルーティングした時Flaskでルーティングしたところあけなきゃいけないのかなぁ・・・・まだまだわからないところがあるので実験して分かったらまた記事を書きます〜

そろそろPyTrochとかの記事書きたいんだけど,如何せんチュートリアルに書いてある以上のことがまだできてない・・・・チュートリアルがある程度理解できたらなにか書くかもしれません

多分MQTTサーバーをFlaskで作ったよ〜って記事が先になると思います

こんな感じで今回は終わりにします.ありがとうございました

よかったらフォローしてね〜

twitter.com