Twitterクローンを作っていく企画の第1回です。
今回から実際に作業を進めていきます。
※ 今回のコードはこちらで確認できます。
今回はクライアントとAPIサーバのプロジェクトをそれぞれ作成し、通信ができるところまで進めます。
はじめにnodeのバージョンを確認しておきます。
$ npm --version
6.14.12
$ node --version
v14.16.1
クライアント側のプロジェクト作成
クライアント側のプロジェクトを作成します。
/path/to/project/
はプロジェクトのルートディレクトリのつもりです。
$ npm install -g @vue/cli
$ cd /path/to/project/
$ vue create client
プリセットの選択を求められたので Manually select features
を選択します。
Babel, Router, Vuex, Linter / Formatter を選択します。
Vue.js のバージョンは 3.x を選択します。
Use history mode for router? は Y を入力しておきます。
linter / formatter の設定は ESLint with error prevention only を選択しておきました。
aditional lint features は Lint on save を選択しました。
設定は In dedicated config files を選択しました。
Vue CLI v5.0.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex, Linter
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Basic
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
とりあえず起動してみます。
$ cd client
$ npm run serve
http://localhost:8080 にアクセスすると無事表示されました。
APIサーバ側のプロジェクトを作成
まずはディレクトリと、Pythonの仮想環境を作ります。
$ cd /path/to/project/
$ mkdir api
$ cd api
$ python3 -m venv api-env
仮想環境を起動します。
$ source ./api-env/bin/activate
下記の内容で、 requirements.txt を作成します。後で constraints.txt も作成する予定なので、ここではバージョンを指定しません。
Flask
それではライブラリをインストールします。
$ pip install -r requirements.txt
constraints.txt を作っておきましょう。
$ pip freeze > constraints.txt
僕の環境では以下の様になりました。
click==8.0.4
Flask==2.0.3
itsdangerous==2.1.0
Jinja2==3.0.3
MarkupSafe==2.1.0
Werkzeug==2.0.3
以後、Pythonのライブラリを追加する際は、requirements.txt にライブラリを追記 → pip install -r requirements.txt -c constraints.txt
→ pip freeze > constraints.txt
という流れで requirements.txt と constraints.txt を更新していきます。
ここで .gitignore も作っておきましょう。プロジェクトのルートディレクトリに下記の内容で作成します。
api-env/
__pycache__/
クライアント側については、vue create client
によって client/.gitignore
が生成されているので現段階ではapi側の仮想環境を無視するだけで良さそうです。
APIサーバとクライアントの通信
apiディレクトリの直下に下記の内容で main.py を作成します。
from flask import Flask, jsonify, session
app = Flask(__name__)
app.secret_key = 'DUMMY'
@app.route("/api/hello")
def hello_world():
if 'count' not in session:
session['count'] = 0
session['count'] += 1
return jsonify({
'count': session['count'],
'message': 'hello'
})
下記で起動できます。仮想環境が起動していないとエラーになるので注意してください。
$ cd /path/to/project/api
$ FLASK_APP=main flask run
この状態で http://localhost:5000/api/hello にアクセスすると {"count":1,"message":"hello"}
のような文字列が表示されることが確認できると思います。
ここからは、クライアント側からAPIが呼び出せるか? と その際にセッションを利用できるか? を確認していきます。
まずはAPI呼び出し用のライブラリをインストールしておきます。
$ cd /path/to/project/client
$ npm install axios
client/src/components/HelloWorld.vue
を下記のように書き換えてAPI呼び出しを試してみます。
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>メッセージ : {{ message }}</p>
<p>カウント : {{ count }}</p>
<button @click=onClick>push</button>
</div>
</template>
<script>
import axios from 'axios';
import { ref } from 'vue';
export default {
name: 'HelloWorld',
props: {
msg: String
},
setup () {
const message = ref('');
const count = ref(0);
const onClick = () => {
axios.get('http://localhost:5000/api/hello')
.then(res => {
message.value = res.data.message;
count.value = res.data.count;
});
};
return {
message,
count,
onClick
};
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
push と書かれたボタンをクリックするとAPIを呼び出してその内容が画面に表示されるはずですが、実際に押してみても反応がありません。ブラウザの開発者ツール等で確認するとわかりますが、CORSでエラーになっています。
これを解消するには、vue.config.js を下記のように修正します。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
"^/api/*": {
target: "http://localhost:5000"
}
}
}
})
あと、先程の client/src/components/HelloWorld.vue
の onClick を下記のように修正しておいてください。
const onClick = () => {
axios.get('/api/hello')
.then(res => {
message.value = res.data.message;
count.value = res.data.count;
});
};
この状態でクライアントを起動すると、ちゃんとAPIを呼び出せることとセッションに保存した値がインクリメントされていくことが確認できると思います。
今回はここまでです。
次回はログイン周りをやっていこうと思います。