趣味WebエンジニアがVue.js+Flask(&GCP)でWebアプリ開発

# きっかけ
　ここ１年くらい、Twitter等のSNSでいろんな方が発信されている自作Webアプリを色々見ているせいか、筆者の中でWeb技術・Web開発に対する熱が高く、なにか便利なWebアプリを作りたいという想いがあります。ただ、バックエンドのAPサーバやDBサーバを構築するための知識は現時点でそこまでありません。
　そこで、「コーディングはなるべくHTMLやJavaScript、CSS（とそれらのフレームワーク）のようなフロントエンド中心に行い、なおかつ積極的にSaaSを使うことでサーバレスでさくっとWebアプリを構築できないか」を模索し、実際にアプリを作成・公開したのでここに手法を書き記します。

# 作成するWebアプリ
　今回作るアプリですが、友人からアイデアをもらい「こんな内容のマンガが読みたい、というざっくりとしたきもちからオススメの作品を推薦するアプリ」を協力して作ることにしました。機能はひとまずシンプルで良いと思ったので、次のような要件で作成します。

- **スマホでのアクセス・閲覧を前提とするがPCでも見られる**
　つまりモバイルファーストのレスポンシブデザインである。

- **Webアプリ内でユーザ認証はなし**
　URLにアクセスするだけで誰でも使える。その代わりサービス内でユーザデータは保持しない（DBサーバの不使用）。

- **ユーザのキーワード入力に対し、必要なものを検索してサイトに表示する**
　ただし、検索はDBに対してではなくHTMLやJSにハードコーディングされたもの、またはデータ検索用に公開されているWebAPIに対して行い、その結果データを取得し表示することとする（DBサーバの不使用）。

- **クライアント(ブラウザ)側で動的なページ構築を行う**
　JavaScriptを使い、取得データを表示するためのhtmlをユーザ側で動的に作成し表示する（APサーバの不使用）。

# 使用するWeb要素技術
　要件を踏まえ、今回使用した言語【フレームワーク】を以下に記します。

- **HTML**

- **CSS【Bootstrap】**
　公式ページはこちら（[Bootstrap - 世界で最も人気のあるフロントエンドのコンポーネントライブラリ](https://getbootstrap.jp/)）。Bootstrapを使うと、整ったデザイン・レスポンシブデザインを楽に作ることができる。

- **JavaScript【Vue.js】**
　公式ページはこちら([Vue.js](https://jp.vuejs.org/))。Vue.jsを使うと、JavaScriptがクライアント（ブラウザ）側でhtmlを操作する動作をかなり直感的に記述できる（データバインディングという仕組みによりJavaScript上のデータを更新するとhtmlも同時に更新される）。

- **Python【Flask】**
　公式ページはこちら（[Flaskへ ようこそ — Flask v0.5.1 documentation](ttps://a2c.bitbucket.io/flask/)）。Flaskを使うと、Pythonの文法を使いシンプルな記述でWebAPIを記述することができるので、もし必要なデータを公開しているWebAPIがなかったらFlaskを使って自分で作成できる。今回はキーワードをもとに作品名一覧を返却するAPIを作成した。

# Webアプリ構築に使用するSaaS
　今回の要件でWebアプリを構築するために使用可能なSaaSの例を以下に記します。

- **さくらインターネット（今回はレンタルサーバライトプランで可）**
　公式ページはこちら（[さくらのレンタルサーバ | 高速・安定WordPressなら！無料2週間お試し](https://www.sakura.ne.jp/)）。HTML、CSS、JavaScript等を配置して公開することができるWebホスティングサービス。その他に、独自ドメイン取得やSSL証明書の設定オプションサービスもある。各種設定は、基本Webインタフェースでポチポチ操作できるので初心者としてはとっつきやすい。無料お試し期間のあとは月額定額制。
　その他、類似のホスティングSaaSとしては、Firebase Hosting([公式ページ](https://firebase.google.com/docs/hosting?hl=ja))や、AWS（[公式ページ](https://aws.amazon.com/jp/websites/)）等があります。これらは、従量課金制で無料枠もあったりするので初期費用を抑えられる。

- **Google App Engine**
　サービスの概要はこちら（[App Engine  |  Google Cloud](https://cloud.google.com/appengine?hl=ja)）。
　上述のFlaskで記述したWebAPIを配置して公開するために利用できる。アクセスや負荷に応じて自動でスケールしてくれ、料金は従量課金制。

# システム構成図
　これまでの話を踏まえ、フレームワーク・SaaSを活用したWebアプリの構成図（例）は以下のようになります。
![システム構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352068/9d5d78e8-f254-8b10-274f-64501341f4ba.png)

　FlaskでWebAPIを公開している部分ですが、Google App Engineにアップロードしているファイル構造は次のようなかんじです。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/352068/7048116d-9e6a-fe25-04d4-864084c17dd7.png)
`data_list.csv`が作品名とその特徴量（タグ）が入ったリストデータ、`main.py`がFlaskのpythonコード、それ以外はApp Engineのお作法で用意する設定ファイルです。設定ファイル作成には、次の記事を参考にさせていただきました。

- [Google App Engine + Flask(Python3)で「Hello Flask!!」してみた part2 ~デプロイする~ - Qiita](https://qiita.com/h_okawa0303/items/a3b9c0f829e708a445b1)
- [PythonのFlaskアプリをGoogle App Engineにデプロイしてみた - Qiita](https://qiita.com/kai_kou/items/775bcc058aaabbdff4e7)

`main.py`の中身は次のようになっており、ユーザがWebAPIに対して作品検索用のデータ(json)を投げてきたときに、結果データ(json)を返却するように記述しています。

```python:main.py
from flask import Flask, jsonify, request
from flask_cors import CORS
import os
import csv


# このスクリプトが在るディレクトリの絶対パスが入る変数
CWD = os.path.dirname(__file__)

# 作品データのファイル名
DATA_LIST_FILE = "data_list.csv"
LEARN_DATA = None  # 推薦に使うデータオブジェクト

# CSVのパスを受け取って読み込み
def loadStractualData(target_file):
    global LEARN_DATA  # グローバル変数に代入するために必要な宣言
    csv_list = []  # 単純にCSVをリストに変換しただけのリスト
    with open(target_file, 'r', encoding='utf-8', newline="") as f:
        csv_list = [row for row in csv.reader(f)]  # 2次元リスト
    output = []
    for row in csv_list:  # CSVを一行ずつ処理
        #################################################
        # CSVの行を構造化データにしてoutputに格納していく処理(割愛)
        #################################################
    print("file loading finished!")
    LEARN_DATA = output

###############################
##  ここからサーバプロセスの設定  ##
###############################
loadStractualData(os.path.join(CWD, LEARNED_FILE)) # CSVファイルを読み込む
app = Flask(__name__)
app.config['JSON_AS_ASCII'] = False  # 出力JSONの日本語を文字化けさせない設定
CORS(app)  # Access-Control-Allow-Originの設定

# HTTPのPOSTで/post_tagsにユーザ選択タグが送られて来たときの処理
@app.route('/post_tags', methods=['POST'])
def post_tags():
    json = request.get_json()  # POSTされたJSONを取得
    input_tags = json["tags"]  # ユーザが入力したタグのリスト
    ###########################################################
    # ユーザの送ってきたタグで作品リストをフィルタしout_listに格納する処理(割愛)
    ###########################################################
    return jsonify({"title_num": len(out_list), "titles": out_list}) #jsonを返す

# python実行時のエントリーポイント
if __name__ == "__main__":
    print(" * Flask starting server...")
    app.run()  # サーバプロセス起動
```

Vue.jsからFlaskで作成したWebAPIにリクエストを投げる部分は、Axiosを使用しています。以下の記事を参考にしました。

- [Vue.jsとAxiosなら驚くほど簡単に作れる！外部APIを使ったWebアプリの実例 - WPJ](https://www.webprofessional.jp/fetching-data-third-party-api-vue-axios/)
- [axios を利用した API の使用 — Vue.js](https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html)

# 完成したアプリ
　完成したアプリはこんな感じです([emore | "きもち"で探すマンガ検索](https://emo-re.com))。トップページ、検索ページ、検索結果ページからなるシンプルなアプリで、要件にあったようにスマホ前提のレスポンシブデザインになっています（Bootstrapのおかげ）。また、検索ページでは、特にVue.jsによるブラウザ側での動的描画が活かせている（ユーザがタグを選択すると逐一WebAPIに送信し結果の表示を更新するような、動きがあるデザインになっている）と思うので、是非見ていただければ幸いです。

# 所感
　Webアプリ開発における、フロントエンド技術やSaaSがかなり発達していて、個人開発でも手軽にある程度のアプリは作れるようになっていると感じます。今回要件に含めなかったユーザ認証にしても、例えばSaaSの[Firebase Authentication](https://firebase.google.com/products/auth?hl=ja)を使えば、マルチプラットフォームログイン(Twitterでログイン、Facebookでログイン等)を実装できますし、ユーザデータを保存するDBにしてもFirebase,FireStore等のWebAPI経由で利用できるものがあります。
　Vue.jsもFlaskも、高機能なWebサービスを作ろうと思ったらいくらでも技術的な発展性を含んでいるので、今後も適度に学んだ知識を作品としてアウトプットしつつ、引き続き技術にもチャッチアップして学習していこうと思います（とりあえず、Vue.jsのフレームワークであるNuxt.jsや、Flaskより高機能なDjangoについて勉強中）。