こんにちは、今回はPythonのWebフレームワークFlaskを用いて、Web APIを作成する方法についてご紹介します。
Flaskは軽量Webフレームワークで、Pythonで人気のWebフレームワーク、Djangoほど多機能ではありませんが、さくっとAPIを作成できるので、私のような非Webエンジニアでも重宝しています。
今回は、このFlaskを用いて、わずか十数分でWeb APIを作成してみましょう!
今回作るもの
PythonでWebAPIを作成し、HTTPリクエストを受け取ったらデータをJSONで返す簡易的なシステムを作成します。
本記事はWindows 10 Pro + Python 3.10.2で検証していますが、Python3系が動く環境であれば再現可能です。
Pythonの環境がない方は、以下を参考に構築してみてください。
Pythonの必要なライブラリをインストールする
ローカルのPython環境に必要なライブラリをインストールします。
$ pip install flask==2.1.2 $ pip install requests==2.28.1
Webアプリケーションを作成していく
今回は以下のリクエストを受け取るAPIを作成します。
GET /api/hello GET /api/articles GET /api/articles/<id> POST /api/articles
ディレクトリ構成は以下の通りです。
. ├── app │ ├── apis │ │ ├── articles.py │ │ └── hello.py │ ├── models │ │ └── articles.py │ └── server.py ├── request.py └── run.py
app/server.py
from flask import Flask from app.apis import hello, articles app = Flask(__name__) app.register_blueprint(hello.api) app.register_blueprint(articles.api)
Flaskアプリケーションを定義するファイルです。
app.register_blueprint()
の箇所で、hello
、articles
の2つのAPIをFlaskアプリケーションに登録しています。
app/api/hello.py
from flask import Blueprint, jsonify, request api = Blueprint('hello', __name__, url_prefix='/api/hello') @api.route('') def get(): name = request.args.get('name', 'World') return jsonify({'message': 'Hello ' + name + '!'}), 200
このファイルで/api/hello
へのリクエストを受け付けるメソッドを定義します。
api = Blueprint()
でAPIを定義(これをapp/server.py
で読込している)し、
get()
のデコレータ@api.route('')
でリクエストを受け取る処理を記述します。
GETのパラメータをは request.args.get('name', 'World')で受け取ります。第1引数がパラメータ名、第2引数がパラメータを指定されなかったときのデフォルト値です。
return jsonify({'message': 'Hello ' + name + '!'}), 200`で、HTTPのレスポンスとなるJSONと、HTTPステータスコードを返します。
app/api/articles.py
from flask import Blueprint, jsonify, request from app.models import articles api = Blueprint('article', __name__, url_prefix='/api/articles') @api.route('') def get_all(): data = articles.get() return jsonify(data), 200 @api.route('/<id>') def get_by_id(id): data = articles.get(id) if len(data) > 0: return jsonify(data), 200 else: return jsonify({'errors': [{'message': 'NOT FOUND'}]}), 404 @api.route('', methods=['POST']) def post(): data = articles.post( str(request.form['title']), str(request.form['link']) ) return jsonify(data), 201
このファイルでは以下のリクエストを処理します。
GET /api/articles GET /api/articles/<id> POST /api/articles
GET /api/articles
はget_all()
でリクエストを受け付けます。
GET /api/articles/<id>
はget_by_id(id)
でリクエストを受け付けます。引数でIDを受け取り、IDに対応するデータを返します。
POST /api/articles
は、post()
でリクエストを受け付けます。デコレータを、@api.route('', methods=['POST'])
と、対応するHTTPメソッドを定義(デフォルトではGETのみを受け付ける)することで、POSTリクエストを処理することができます。
POSTリクエストで受け取ったデータは、request.form['title']
のようにして受け取ることができます。
これらのメソッド内のビジネスロジックは、このファイルではなく、次のファイルに記述しています。
app/api/models/articles.py
def get(id: int = None): data = [ { 'id': '1', 'title': 'Cloud FunctionsでGoogle Search Consoleのデータ収集を完全自動化する', 'link': 'https://www.true-fly.com/entry/2022/04/18/080000', }, { 'id': '2', 'title': 'PythonでGoogle Search ConsoleのデータをBigQueryにロードする', 'link': 'https://www.true-fly.com/entry/2022/04/11/073000', }, { 'id': '3', 'title': '【TypeScript超入門】TypeScript + webpackでWebアプリケーション開発環境を構築する', 'link': 'https://www.true-fly.com/entry/2022/03/14/080000', }, ] if id: for row in data: if row['id'] == id: return row return {} else: return data def post(title:str, link:str): print(title) print(link) return { 'id': '4', 'title': title, 'link': link, }
記事のデータを扱うモジュールです。
get()
では、idが指定されていれば指定のデータを、存在しなければ空の辞書を、指定されていなければ全データを返します。
post()
では実際にDBにデータを登録する処理は記述せず、値を受け取ったら標準出力して、辞書の形でデータを返すようにしています。
run.py
import logging import os logging.basicConfig(level=logging.DEBUG) from app import server if __name__ == '__main__': server.app.run(host='localhost', port=int(os.environ.get('PORT', 9000)))
ローカルホストのPORT9000で開発用HTTPサーバを起動するモジュールです。
以上でWebAPIの完成です!
次に、このWeb APIにリクエストを送るモジュールを作成してみます。
request.py
import requests def get(url): response = requests.get(url) print(url) print(response.status_code) print(response.text) def post(url, data): response = requests.post(url, data=data) print(url) print(response.status_code) print(response.text) if __name__ == '__main__': # helloパラメータなし url = 'http://localhost:9000/api/hello' get(url) # helloパラメータあり url = 'http://localhost:9000/api/hello?name=Truefly' get(url) # articles 全件取得 url = 'http://localhost:9000/api/articles' get(url) # articles ID1取得 url = 'http://localhost:9000/api/articles/1' get(url) # articles ID7取得 url = 'http://localhost:9000/api/articles/7' get(url) # ariticles 登録 url = 'http://localhost:9000/api/articles' data = { 'title': 'TypeScriptはじめました', 'link': 'https://www.true-fly.com/entry/2022/03/09/073000', } post(url, data)
Flaskアプリケーションを起動した状態で、このモジュールを実行すればAPIのテスト実行できます。
実際に実行してみる
全ファイルを作成したら、ターミナルでrun.py
を実行してWebサーバを起動させます。
$ python run.py * Serving Flask app 'app.server' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off INFO:werkzeug: * Running on http://localhost:9000 (Press CTRL+C to quit)
次に別のターミナルを起動し、request.py
を実行して、APIリクエストを送ってみましょう。
$ python request.py http://localhost:9000/api/hello 200 {"message":"Hello World!"} http://localhost:9000/api/hello?name=Truefly 200 {"message":"Hello Truefly!"} http://localhost:9000/api/articles 200 [{"id":"1","link":"https://www.true-fly.com/entry/2022/04/18/080000","title":"Cloud Functions\u3067Google Search Console\u306e\u30c7\u30fc\u30bf\u53ce\u96c6\u3092\u5b8c\u5168\u81ea\u52d5\u5316\u3059\u308b"},{"id":"2","link":"https://www.true-fly.com/entry/2022/04/11/073000","title":"Python\u3067Google Search Console\u306e\u30c7\u30fc\u30bf\u3092BigQuery\u306b\u30ed\u30fc\u30c9\u3059\u308b"},{"id":"3","link":"https://www.true-fly.com/entry/2022/03/14/080000","title":"\u3010TypeScript\u8d85\u5165\u9580\u3011TypeScript + webpack\u3067Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u74b0\u5883\u3092\u69cb\u7bc9\u3059\u308b"}] http://localhost:9000/api/articles/1 200 {"id":"1","link":"https://www.true-fly.com/entry/2022/04/18/080000","title":"Cloud Functions\u3067Google Search Console\u306e\u30c7\u30fc\u30bf\u53ce\u96c6\u3092\u5b8c\u5168\u81ea\u52d5\u5316\u3059\u308b"} http://localhost:9000/api/articles/7 404 {"errors":[{"message":"NOT FOUND"}]} http://localhost:9000/api/articles 201 {"id":"4","link":"https://www.true-fly.com/entry/2022/03/09/073000","title":"TypeScript\u306f\u3058\u3081\u307e\u3057\u305f"}
まとめ
以上、今日はPythonで簡単なWeb APIを作る方法について紹介しました。
今回はローカル環境での実装まででしたが、GCPのサービスを
Flaskについては当ブログでも何度か取り上げてますので、参考になれば幸いです。