シンプルにFlaskでAPIを作って、jQueryとかAjaxとか使わない素のJavaScriptでAPIを実行してブラウザ上で表示したいときのまとめ。
JavaScript単体では難しい処理を実装したいときや、Pythonで実装した処理のフロントを手っ取り早く実装したいときに使えると思います。
TL;DR
- JavaScriptのFetch APIでAPI実行する
- Flask(Python製のウェブアプリケーションフレームワーク)でAPI自作する
- おまけで、Flask環境をDockerで作る場合のファイル一式紹介
JavaScriptでAPI実行
Fetch APIを使うと素のJavaScriptでも簡単にAPIを実行できることを知った。
具体的には、例えば以下のようなコードを実行するとurl
に指定したAPIの実行結果を取得/加工/表示することができる。
function get(url) {
fetch(url)
.then(function(response) {
return response.text(); // ここのtextをjsonやblobに変えると取得形式が変わる
})
.then(function(text) { // 引数指定すると↑でreturnしたオブジェクトが入る(thenでチェーンしていける)
// 加工や表示などの処理
});
}
簡単なHTMLと加工部分をまとめて一緒に書くと以下のような感じ。
ボタンを押すとテキストボックスに入力されたテキストがPostされ、Post後にGetの実行結果が表示される。
PostとGetの具体的な処理は下記のFlaskのコードhoge.py
を参照
Postで送るときのパラメータの指定方法で困ったが、以下のstackoverflowに書いてあった方法で解決した。
How do I post form data with fetch api?
<html>
<head>
<title>APIテスト</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script>
function get_func(url) {
fetch(url)
.then(function(response) {
return response.text();
})
.then(function(text) {
let view = document.getElementById("view")
view.textContent = ""
// 取得テキストを一行ごとにループ(ただ改行して表示しているだけ)
text.split("\n").forEach((value) => {
view.insertAdjacentHTML('beforeend', value);
view.insertAdjacentHTML('beforeend', "<br>");
})
});
}
function post_func(url) {
// Postで送るパラメータを作成
let formData = new FormData();
formData.append('param', document.getElementById('post_param').value);
fetch(url, {
method: 'POST', // methodを指定しないとGETになる
body: formData, // Postで送るパラメータを指定
})
.then(function() { // Postした後に結果をGetする(コールバックなのでPostが実行完了してから実行される)
get_func('APIのGet用URL'); // 今回は「http://192.168.1.100:4000/get」
});
// ここにget_funcを書くとPostとGetがほぼ同時に行われてしまい、Post結果をGetできない
// get_func('APIのGet用URL');
}
</script>
</head>
<body>
<input type="text" id="post_param" size=20 value="hoge">
<input type="submit" value="送信" onClick="post_func('APIのPost用URL')"> <!-- 今回は「http://192.168.1.100:4000/post」-->
<div id="view"></div>
</body>
</html>
FlaskでAPI作成
Flask(フラスク)は、プログラミング言語Python用の、軽量なウェブアプリケーションフレームワークである。
出展:Wikipedia「https://ja.wikipedia.org/wiki/Flask」
基本的な使い方はググればたくさん出てくるので省略
なお、ローカルや別ドメインからAPIを実行しようとするとクロスドメイン制約で拒否られる。
Flask-CORSを入れてCORS(Cross Origin Resource Sharing)を有効にしておくとこれを防げる。
from flask import Flask, jsonify, abort, make_response, render_template, request
from flask_cors import CORS
api = Flask(__name__)
CORS(api) # CORS有効化
@api.route('/get', methods=['GET']) # Getだけ受け付ける
def get(): # 関数名は重複していなければなんでもよい
result = ""
# ローカルのファイルを全部読み込んで返すだけ
with open("./datafile", mode='r') as f:
result += f.read()
return result
@api.route('/post', methods=['POST']) # Postだけ受け付ける
def post():
result = request.form["param"] # Postで送ったときのパラメータの名前を指定する
# パラメータをローカルのファイルに書き込むだけ
with open("./datafile", mode='a') as f:
f.write(result + "\n")
return make_response(result)
# 4000番ポートでWebサーバを起動する
if __name__ == '__main__':
api.run(host='0.0.0.0', port=4000, debug=True)
これを実行するとWebサーバが起動し、http://サーバIP:4000/get
などのURLで実行することが可能になる。
前述したJavaScriptと合わせると、簡易的なフローは以下になる。
-
post_param
に文字を入力して送信ボタン
を押下(クライアント側処理) - JavaScriptで定義した
post_func
関数が実行される(クライアント側処理) -
http://サーバIP:4000/post
が呼ばれる(クライアントからサーバへのRequest) - Flaskで定義した
post
関数が実行される(サーバ側処理) -
post
関数実行結果が返ってくる(サーバからクライアントへのResponse) - Post処理実行完了後にJavaScriptで定義した
get_func
関数が実行される(クライアント側処理) -
http://サーバIP:4000/get
が呼ばれる(クライアントからサーバへのRequest) - Flaskで定義した
get
関数が実行される(サーバ側処理) -
get
関数実行結果が返ってくる(サーバからクライアントへのResponse) -
get_func
関数内でget
関数の実行結果を加工して表示する(クライアント側処理)
これでAPIを自作して呼び出すことができるようになった。
Dockerの諸々のファイル紹介
特に説明はしません。
FROM python:3-alpine
RUN mkdir /test
WORKDIR /test
COPY requirements.txt /test/
RUN pip install -r requirements.txt
CMD ["python3","code/hoge.py"]
flask
flask-cors
version: '3'
services:
test:
build: ./test/build/
tty: true
restart: always
ports:
- 4000:4000
volumes:
- /etc/localtime:/etc/localtime:ro # ホストと時刻動機
- ./test/data/:/test
.
├── docker-compose.yml
└── test
├── build
│ ├── Dockerfile
│ └── requirements.txt
└── data
├── code
│ ├── hoge.py # Flaskのコード
│ ├── static # サーバ内にHTMLファイルなど置きたかったらこのあたりを使う
│ └── templates # サーバ内にHTMLファイルなど置きたかったらこのあたりを使う
└── datafile # Post時に自動生成されるファイル
なお、冒頭の画像ではtemplates
にindex.html
を配置してhoge.py
に/
アクセス時にindex.html
を表示するコードを書いてアクセスしていますが、
index.html
をローカルに置いてアクセスしても動きます。