6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PythonでwebApi作成 (CRUD) 初心者の方に向けて

Posted at

この記事の目的

DBに対するCRUD操作を行えるwebサーバを作成する。
丁寧に解説しました。
まさかりを歓迎します。

緒言&前提

○前提
・仮のDBとしてlist型を作成し、そこに対してCRUD操作を行います。
仮DBに対する操作を実際のDBに対する操作に書き換えれば良いかと思います。
・python、pip(pythonのパッケージマネージャ)のインストールを前提とします。
○緒言
pythonでwebApiを作成するモチベーションとしては、
・DBデータを数学的に扱うためにnumpyライブラリを使用したいから
というところでしたが、あとから調査してみると、web通信自体はjsなどに任せて、データ処理のみをpython+numpyに任せた方が高速だということでした。
参考:https://qiita.com/KatsunoriNakamura/items/dd567ea7cfaa99685453

言葉

・Flask: python上で動くウェブアプリケーションフレームワーク。かんたんにwebアプリが作れました。
・webApi: この記事では、URIを叩くとDBに対する操作をおこなってくれるwebサーバを指す。

概要

1.Flaskをインストール
2.Apiファイルを作成

1.Flaskをインストール

コマンドラインから、以下のコマンドを打ちます。

pip install Flask

2.Apiファイルを作成

説明の流れとして、まずコード全体を示したあとに、簡単に各コードの解説していきます。

webAPIファイルの全貌

以下のファイルを作成し、実行することでサーバが起動します。
サーバ起動中に、CRUDメソッドに設定したURIを叩くことで、DBを操作できます。

sampleapp.py
from flask import Flask, jsonify, request, render_template

app = Flask(__name__)

# DB
stores = [
    {
        'name': 'my_store',
        'items': [
            {
            'name': 'chocolate',
            'price': 120
            }
        ]
    }
]

# storeに対するCRUD--------------
# GET /store/<string:name>
@app.route('/stores/<string:name>') # 'http://127.0.0.1:5000/store/some_name'
def get_store(name):
    for store in stores:
        if store["name"] == name:
            return jsonify(store)
    return jsonify({"message": "no store named {} found.".format(name)})

# POST /store data: {name:}
@app.route('/stores', methods=['POST'])
def create_store():
    request_data = request.get_json()
    store = next(filter(lambda x: x["name"]==request_data["name"], stores), None)
    if store != None:
        return jsonify({"message": "store named {} already exist.".format(request_data["name"])})
    else:
        new_store = {
            "name": request_data["name"],
            "items": request_data["items"]
        }
        stores.append(new_store)
        return jsonify({"message": "{} store is added.".format(request_data["name"])})

# PUT /store data: {name:}
@app.route('/stores/<string:name>', methods=['PUT'])
def update_store(name):
    request_data = request.get_json()
    store = next(filter(lambda x: x["name"] == name, stores), None)
    if store == None:
        return jsonify({"message": "no store named {} found.".format(name)})
    else:
        store["items"] = request_data["items"]
        return jsonify({"message": "{} is updated.".format(name)})

# DELETE /stores/<string:name>
@app.route('/stores/<string:name>', methods=['DELETE'])
def delete_store(name):
    global stores
    stores = list(filter(lambda x: x["name"] != name, stores))
    return jsonify({"message": "Delete store named {}".format(name)})

# --------------------storeに対するCRUD

# GET /stores
@app.route('/stores')
def get_stores():
    return jsonify({'stores': stores})

# ホーム画面にhtmlを読み込んでみる。
# GET /
@app.route('/')
def home():
    return render_template("index.html")

app.run(port=5000)

解説

sampleapp.py
from flask import Flask, jsonify, request, render_template

Flaskライブラリから必要なモジュールをインポートしています。

sampleapp.py
app = Flask(__name__)

アプリケーション本体を作成します。
pythonでは、アンダースコアでかこまれた特別なデフォルト変数があり、nameはファイル名にあたりますので、今回の場合sampleappにあたります。
ただし、実行ファイル(ターミナルからpython ~で実行したファイル)のnameはmainを返します。
Flaskは実行ファイル上でしか正しく動作することができないため、呼び出されたファイルについてname=mainであることを確認しています。

sampleapp.py
# DB
stores = [
    {
        'name': 'my_store',
        'items': [
            {
            'name': 'chocolate',
            'price': 120
            }
        ]
    }
]

仮のDBです。
ストアが複数格納され、各ストアはストア名と複数の商品データがはいるとしています。

sampleapp.py
# GET /store/<string:name>
@app.route('/stores/<string:name>') # 'http://127.0.0.1:5000/store/some_name'
def get_store(name):
    for store in stores:
        if store["name"] == name:
            return jsonify({"stores": store})
    return jsonify({"message": "no store named {} found.".format(name)})

GETメソッドです。
ストア名を指定して、存在すればjson型のレスポンスで返しています。
ストアが存在しない場合もメッセージをjson型のレスポンスで返しています。

@app.route('/stores/<>')でappにURIを登録しています。(デフォルトIPは'http://127.0.0.1:5000'に自動的に指定されます。)
このURIが叩かれたときに、下のメソッドが呼ばれます。引数にURI中の<>を代入しています。
jsonify( )は辞書型からjson型を作成するメソッドです。

sampleapp.py
# POST /store data: {name:}
def create_store():
    request_data = request.get_json()
    store = next(filter(lambda x: x["name"]==request_data["name"], stores), None)
    if store != None:
        return jsonify({"message": "store named {} already exist.".format(request_data["name"])})
    else:
        new_store = {
            "name": request_data["name"],
            "items": request_data["items"]
        }
        stores.append(new_store)
        return jsonify({"message": "{} store is added.".format(request_data["name"])})

POSTメソッドです。
URI指定の際に、POSTを指定しています。(デフォルトはGETが指定されています。)
request.get_json()でリクエストボディを取得できます。
同じ名前のストアがなければ、リクエストボディのデータを持ったストアをデータベースに加えます。

PUTメソッドとDELETEメソッドについては、特に追加情報がないので割愛します。

sampleapp.py
# GET /stores
@app.route('/stores')
def get_stores():
    return jsonify({'stores': stores})

CRUD操作の確認用にDB全体を取得するAPIをつくっておきました。

sampleapp.py
#ホーム画面にhtmlを読み込んでみる。
# GET /
@app.route('/')
def home():
    return render_template("index.html")

htmlファイルを呼び出せます。
呼び出し先で、DB全体に対するGETメソッドを呼び出すように設定しています。
スクリーンショット 2020-10-06 1.45.12.png

sampleapp.py
app.run(port=5000)

最後にアプリケーションを起動する記述をします。
ポート番号を指定しなくてもデフォルト5000がデフォルトなのですが、明言するためにあえて書いています。
もちろん他のポート番号も指定できます。

動作確認

実行

$ python sampleapp.py
 * Serving Flask app "sampleapp" (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
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

確認

Postman(HTTPリクエストが簡単に行えるツール)を使用して確認しました。
CRUDapiの動作が確認できました。

GET (stores)

stores全体のデータを取得します
スクリーンショット 2020-10-05 23.49.29.png

POST

新しいストアをりクエストbodyに入れて登録します。
スクリーンショット 2020-10-06 0.15.22.png
確認 (GET (stores))
スクリーンショット 2020-10-06 0.15.41.png

ホーム画面

スクリーンショット 2020-10-06 0.25.41.png

他のCRUDも同様に動作します。

感想

python/Flaskを使用すれば、
短時間に簡易なコードでwebAPIを作成していけそうです。

当初の目的には使用しないので...ボットwebApiとかとして弔ってあげたいと思います。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?