VueなどのSPAを使った際のREST APIの設計

# 1.はじめに
バックエンドとフロントエンドのフレームワーク両方学習し終わった皆さん、本格的に両方を用いたWebアプリ制作を始めると思います！その中の道しるべになればいいなと考えているので、ぜひ見ていってください！
今回は組み合わせ方の中で最も有名であるRESTfulな通信をするREST APIを紹介したいと思います！
### 1-1.使用する環境について
```shell:
Python           3.9.13
Flask            2.2.2
Flask-Cors       3.0.10
Node.js          v16.17.0
@vue/cli         5.0.8
```

# 2.前提
### 2-1.フロントエンド
#### 2-1-1.フロントエンドの知識
フロントエンドを勉強し終わった人は以下の知識があることを前提としています。

- `Vue.js`や`React`の書き方を知っている
- これらにおいてSPAで実装できる
- つまり、Routingができる

まだの人は、学習頑張ってください！

#### 2-1-2.フロントエンド終了後の想定される疑問
`firebase`などのBaaSやSaaSなどを利用しての実装はわかったけど、どうやってバックエンドとつながるのだろう
### 2-2.バックエンド
#### 2-2-1.バックエンドの知識
バックエンドを勉強し終わった人は以下の知識があることを前提としています。

- `Flask`、`Ruby on Rails`, `Django`, `Express.js`などのバックエンドの書き方を知っている
- DBの知識は今回は問いません！

#### 2-2-2.バックエンド終了後の想定される疑問
バックエンドを勉強してると、大体htmlを表示できる特殊な手法(`erb`など)が出てきたけど、フロントエンドとの連携させる場合はどのようにすればいいのかわからない

# 3.どう連携させる？
基本的に、サーバー側とクライアント側での通信を行うように設計します。
<img src="https://www.infraeye.com/wp-content/uploads/2020/07/zblogsdn001.gif">
引用:https://www.infraeye.com/2020/07/05/network051/

実はいろいろ方式があり、`SOAP`,`XML-RPC`などがありますが、今回は<font color="Red">**REST**</font>という方式を使ったものを紹介します！(SOAPやXML-RPCが気になる人は調べてみてね！)

具体的には、バックエンドを**API**(データをやり取りするもの)として動作させていきます！

# 4.REST APIとは
REST APIはRESTful APIとも呼ばれますが、大体以下の条件を満たすもののことを指します。
- HTTPメソッドによって、通信を行う
- あらかじめ、**データの形式を決めて通信する**(大体JSON形式)
- **URI(Webだと大体URL)でアクセスする**
- APIの処理が1回で完結する

# 5.実装
今回は`Flask`と`Vue3`を用いて実装していきます
形態としては、同じサーバー上に実装する感じで行きたいと思います！(FlaskでVueをホスティングする)
もし、別サーバーで実装したい場合は、CORS設定を追加してください！
細かい構築方法は[こちらの記事](https://qiita.com/y-tsutsu/items/67f71fc8430a199a3efd)で書いてくれていますのでご覧ください！
#### ディレクトリ構造
```
practice
  ├─backend (Flask)
  └─frontend (Vue.js)
```
#### バックエンド(Flask)側
まず、ローカルPCにFlaskが入ってない人はインストールしましょう(バックエンドを別サーバーからのアクセスを許可したい場合はflask_corsも入れましょう)
```shell
$ pip install flask
```
バックエンド側のコード全文
```python:practice/backend/app.py
from flask import Flask, request, jsonify
from flask_cors import CORS # cors設定する人は追加する

app = Flask(__name__,static_folder='../frontend/dist/static', template_folder='../frontend/dist')#vueのbuildファイルのインポート

@app.route('/', defaults={'path': ''})#ホスティングの設定
@app.route('/<path:path>')
def index(path):
    return render_template('index.html')

@app.route("/api/get",methods=["GET"])#GETメソッドでの処理
def say_hello():
    return jsonify({"say":"hello"})

@app.route("/api/post",methods=["POST"])#POSTメソッドでの処理
def say_name_hello():
    name = request.json["name"]
    comment = f"hello {name}-san!!!"
    return jsonify({"say":comment})

if __name__ == '__main__':
    app.run()
```


#### フロントエンド(Vue)側

Vue-CLI想定で作成しています

##### 下準備
Flaskとの連携を行うために下準備を行います
-  `vue.config.js`に以下の文を加えましょう
```javascript:practice/frontend/vue.config.js
module.exports = {
  assetsDir: 'static',
};
```
- `favicon.ico`の場所の配置をこのように変えましょう
```
frontend
  └─public
      ├─static
      │   └─img
      │       └─favicon.ico
      └─index.html
```
- それに合わせて`frontend/public/index.js`を書き換えましょう
```diff:public/index.html
   <head>
-    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <link rel="icon" href="<%= BASE_URL %>static/img/favicon.ico">
     ...
   </head>
```
##### axiosの導入
フロント側でリクエストを送る機能を作っていきましょう
まず、リクエストを送るのに`axios`を用いていきたいと考えていますので、下記を実行しましょう
```shell
$ npm install axios
```

そしてリクエスト用の関数を記述していくため、
src下にfunctionsディレクトリを作成してreqs.jsを作成しましょう
```js:practice/frontend/src/functions/reqs.js
import axios from "axios"
export const get = async function(){
    try {
        const response = await axios.get("/api/get")// /getにGETメソッドでのリクエストを送る
        return {...response.data, error: false}
    } catch(e) {//通信失敗したときの処理を記述する
        console.log(e)
        return {error: true}
    }
}
export const post = async function(obj){
    try {
        const response = await axios.get("/api/post",obj)// /postにPOSTメソッドでのリクエストを送る, 送信データはobjに入っている
        return {...response.data, error: false}
    } catch(e) {//同上
        console.log(e)
        return {error: true}
    }
}
```
今書いたこれらの関数を実際のvueファイルので用いていきましょう！
今回はただ表示させるだけの内容にしてみました！
```vue:practice/frontend/src/App.vue
<template>
  <div>{{ getComment.say }}</div>
  <div>{{ postComment.say }}</div>
</template>

<script>
import { get, post } from "./functions/reqs.js"//functionsからインポートしてくる
export default {
  data() {
    return {
      getComment: "",//getで取得したオブジェクトを格納する変数
      postComment: "",//postで取得したオブジェクトを格納する変数
    }
  },
  async created() {
    this.getComment = await get()//getを実行して代入
    this.postComment = await post(//たけしという名前をpostして戻り値を代入
      {
        name: "Takeshi"
      }
    )
    console.log(this.getComment)//オブジェクトを見てみよう!!
    console.log(this.postComment)//オブジェクトを見てみよう!
  },
}
</script>
```

#### 実行
これでフロントエンド側の実装が完了しました！
では早速ビルドして実行してみましょう！！
まずフロントエンドをビルドします

```shell
$ npm run build
```
そして、Flaskを起動します
```
$ python app.py
```
そこで起動されるURLから実行結果が下のようになれば成功です👏
![成功写真](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2550660/81ce1380-4f03-73df-391e-0a4f4eea4e3f.png)

# 6.おわりに
いかがだったでしょうか？
本記事ではSPAでREST APIを作成、利用する方法について述べてきました。
そもそも、フロントエンドとバックエンドの両方ともやっている時点で知識は十分身についていると思います。あとは組み合わせ方をいくつか学べば、作れるWebアプリの幅が一気に広がりますので頑張りましょう！
最後までご覧いただき、ありがとうございました。