今回はインターンシップの事前準備としてFlaskでREST APIを実装したときのことについて書きます。
今回はUdemy講師酒井潤さんの「現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル」の157. Flaskを参考に実装しました。上記の講座のリンクは以下の通りです。(ご本人から許可をいただいたうえでブログを掲載しております)
https://www.udemy.com/course/python-beginner/learn/lecture/8451958#overview
また、こちらの記事も参考にさせていただきました。
先に実装の流れと処理の流れについて全体像を示します。
実装の手順
-
必要なライブラリのインポート
Flaskや必要なモジュールをインポートします。
-
main関数の作成(サーバーの起動)
Flaskアプリケーションを初期化し、サーバーを起動する関数を定義します。
-
エンドポイントの設定
各APIエンドポイントのルーティングを@app.routeデコレータで設定します。
-
HTMLファイルの作成
templatesフォルダ内にHTMLファイルを作成し、必要なコンテンツを記述します。
-
レンダリング設定
render_template関数を使用して、HTMLファイルをレンダリングする処理を実装します。
-
CRUD処理の実装
データの作成、読み取り、更新、削除の各機能を実装します。
-
DB接続設定
データベースへの接続、切断、テーブル作成などの処理を実装します。
-
テスト用requestの作成
APIのテストを行うためのPythonスクリプトを作成し、各エンドポイントをテストします。
処理の流れ
main()
- リクエスト受信
- APIを叩いてリクエストを送信
- リクエストのHTTPメソッドに応じて処理が実行される
- GET : データの取得
def example1()
- POST : 新規データの作成
def example2()
- PUT : データの更新
def example3()
- DELETE: データの削除
def example4()
- GET : データの取得
- HTMLをレンダリングし、クライアントに表示
example.html
次に、それぞれについてみていきましょう。
また、今回はデモとして、サッカーのクラブ名を自由に追加したり削除したりできるようなアプリケーションを作りましょう。
- 必要なライブラリのインポート
import sqlite3
from flask import Flask
from flask import g
from flask import render_template
from flask import request
from flask import Response
とりあえずインポートしました。個々のライブラリについては出てきたときに説明します。
- main関数(サーバーの起動)
app = Flask(__name__)
def main():
create_table()
app.run(debug=True)
if __name__ == '__main__':
main()
このように記述します。
app
でFlask アプリケーションを作成します。
app.run
は通常main関数内に記述します。
2.エンドポイントの設定
@app.route('/')
@app.route('/clubs', methods=['GET'])
@app.route('/club', methods=['POST'])
@app.route('/club/<name>', methods=['DELETE'])
3.HTMLファイルを記述
./templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Soccer Clubs</title>
</head>
<body>
<h1>Welcome to Soccer Club Management</h1>
<p><a href="/clubs">View Club List</a></p>
</body>
</html>
./templates/clubs.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Soccer Clubs</title>
</head>
<body>
<h1>Soccer Clubs List</h1>
<ul>
{% for club in clubs %}
<li>{{ club[0] }}</li>
{% endfor %}
</ul>
<h2>Add a New Club</h2>
<form action="/club" method="POST">
<input type="text" name="name" placeholder="Club Name" required>
<button type="submit">Add Club</button>
</form>
</body>
</html>
templatesディレクトリ内のclubs.html
に記述します。
clubnameについては、後ほどDBでclubname
カラムを定義します
4.レンダリング設定
# メインエンドポイント
@app.route('/')
def index():
return render_template('index.html')
レンダリングにはrender_template
を使用します。
render_template
は、Flaskアプリケーション内のtemplates
内に置かれているHTMLファイルを読み込み、レンダリングします。そして、必要な変数を埋め込んだ結果をブラウザに表示します。
5.DB接続設定
# サッカークラブのテーブルを作成
def create_table():
db = get_db()
db.execute(
'CREATE TABLE IF NOT EXISTS clubs (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)'
)
db.commit()
# データベースの接続を取得
def get_db():
if 'db' not in g:
g.db = sqlite3.connect('soccer_clubs.db')
return g.db
# リクエスト終了時にデータベース接続を閉じる
@app.teardown_appcontext
def close_db(exception):
db = g.pop('db', None)
if db is not None:
db.close()
ここでは以下の処理を行います。
① clubs
テーブルの作成
② DBを呼び出す関数の作成(get_db
)
③ DB接続を切る関数の作成(close_db
)
6.CLUD処理
# クラブの一覧表示
@app.route('/clubs', methods=['GET'])
def list_clubs():
db = get_db()
clubs = db.execute('SELECT name FROM clubs').fetchall()
return render_template('clubs.html', clubs=clubs)
# クラブの追加
@app.route('/club', methods=['POST'])
def add_club():
club_name = request.form['name']
db = get_db()
db.execute('INSERT INTO clubs (name) VALUES (?)', (club_name,))
db.commit()
return jsonify(message=f"Club '{club_name}' added."), 201
# クラブの削除
@app.route('/club/<name>', methods=['DELETE'])
def delete_club(name):
db = get_db()
db.execute('DELETE FROM clubs WHERE name = ?', (name,))
db.commit()
return jsonify(message=f"Club '{name}' deleted."), 200
ここでは以下の処理を行います。
① HTTPメソッド(GET
, POST
, DELETE
)に応じたルーティング
② DBコネクションをとってくる(db = get_db()
)
③ SQL文の実行(db.execute()
)
④ DB内のデータの変更を確定(db.commit()
)
7.テスト用request
import requests
def test_list_clubs():
response = requests.get("http://127.0.0.1:5000/clubs")
print(f"List Clubs Response: {response.status_code}")
print(response.text) # HTMLを表示
def test_add_club(club_name):
response = requests.post("http://127.0.0.1:5000/club", data={'name': club_name})
print(f"Add Club Response: {response.status_code}, {response.json()}")
def test_delete_club(club_name):
response = requests.delete("http://127.0.0.1:5000/club/{club_name}")
print(f"Delete Club Response: {response.status_code}, {response.json()}")
if __name__ == "__main__":
# クラブの追加
test_add_club("Arsenal")
test_add_club("Manchester United")
# クラブの一覧表示
test_list_clubs()
# クラブの削除
test_delete_club("Arsenal")
# 削除後に再度クラブの一覧表示
test_list_clubs()
ここでは、request
ライブラリを使ってAPIリクエストを送信するテスト用ファイルを作成します。
まとめ
上記のような流れで実装していくことで、簡単なREST APIが実装できるかと思います。なお、現時点で動作確認はまだ行っていないためこの通りにやっても上手くいかない可能性があります。不具合等ございましたら、お手数ですがコメントにて教えていただけると幸いです。