【入門】Flask + Python で REST API を設計・実装

REST API (Representational State Transfer API)

REST API (Representational State Transfer API) とは、以下の6つの REST アーキテクチャの制約に準拠する API のことです。

  • Client-Server (クライアントとサーバーの分離)
  • Stateless (ステートレス性)
  • Cache (キャッシュ可能性)
  • Uniform Interface (統一されたインターフェース)
  • Layered System (階層化されたシステム・アーキテクチャー)
  • Code-On-Demand (コードオンデマンド) [オプション]

上の説明だけ読んでもよくわからないと思うので、実例を見ていきましょう。

REST API の定義は引用元が O'Reilly のものや、企業のドキュメントを重視しました。

https://en.wikipedia.org/wiki/Representational_state_transfer
https://www.redhat.com/ja/topics/api/what-is-a-rest-api
https://www.ibm.com/jp-ja/cloud/learn/rest-apis
https://docs.oracle.com/cd/E28613_01/web.1211/b65960/overview.htm
スポンサーリンク

初めに

本記事は Web サーバー構築の第6回「REST API」編です。

スポンサーリンク

例:Twitter の REST API の仕様

今回は例として Twitter 社が公開している REST API をみていきます。

Twitter 社の REST API を見ると以下の操作が可能です。

URI ベースのエンドポイントで「リソース」を決める

次のように「URI ベースのエンドポイント」と「リソース」が対応しています。

Twitter の URI ベースのエンドポイント対応するリソース
https://api.twitter.com/2/tweets/:idツイート
https://api.twitter.com/2/users/:id/followingフォローしているユーザー
https://api.twitter.com/2/users/:id/likesお気に入り(ふぁぼ)したツイート

HTTP メソッドで、リソースの「操作」を決める

REST API では次のように、「HTTP メソッド (操作)」と「URI (リソース)」を組み合わせることで、リソースを操作します。

HTTP
メソッド
HTTP メソッドの操作内容HTTP メソッドと URI エンドポイントの組
GETリソースを取得GET https://api.twitter.com/2/tweets/:id
ツイートの取得
POSTリソースを追加
(冪等性無し)
POST https://api.twitter.com/2/tweets
ツイートの投稿
PUTリソースの作成 or 置き換え
(冪等性あり)
ツイートは置き換え (上書き) できない
= 該当する Twitter の API は無い
DELETEリソースを削除DELETE https://api.twitter.com/2/tweets/:id
ツイートを削除

次に Twitter 社の REST API の仕様が、REST アーキテクチャの6つの制約にどのように関わってくるか確認します。

スポンサーリンク

HTTP ベースの REST API とは

HTTP ベースの REST API では、次の2つの条件を満たす必要があります。(正確にはこちら)

  • URI ベースのエンドポイントで「リソース」を決める (https://api.twitter.com/)
  • HTTP メソッドで、リソースの「操作」を決める (GET, POST, PUT, DELETE)

つまり先ほど示した Twitter 社の REST API が持つ特徴そのものです。

この条件により、REST アーキテクチャの6つの制約を満たします。

REST アーキテクチャの制約HTTP ベースの REST API が持つ性質
Client-Server (クライアントとサーバーの分離)HTTP プロトコルはサーバークライアントモデル
Stateless (ステートレス性)HTTP プロトコルはステートレス
Cache (キャッシュ可能性)HTTP ヘッダーでキャッシュの指定可能
Uniform Interface (統一されたインターフェース)※1 URI を利用してリソースを識別
※1 HTTP メソッドを利用してリソースの操作を表現
Layered System (階層化されたシステム・アーキテクチャー)HTTP プロトコルは階層化可能。以下例
ロードバランサー > Web サーバー > AP サーバー
Code-On-Demand (コードオンデマンド) [オプション]オプション

※1

Identification of resources - You use the URI (IRI) standard to identify a resource. In this case, a resource is a web document.

Manipulation of resources through these representations - You use the HTTP standard to describe communication. So for example GET means that you want to retrieve data about the URI-identified resource. You can describe an operation with an HTTP method and a URI.

https://stackoverflow.com/questions/25172600/rest-what-exactly-is-meant-by-uniform-interface

REST API のサンプル

ここでは、Python + Flask を利用して実際に REST API サーバーを作成します。

Flask の詳細については以下の記事をご覧ください。

作成する REST API の設計

ここでは、以下のような Twitter のツイート機能を持つ REST API を作成します。

REST APIREST API の機能
GET /tweetツイートを取得
POST /tweetツイートを投稿
PUT /tweet/:id指定した ID のツイートを更新
DELETE /tweet/:id指定した ID のツイートを削除

REST API サーバーを作成

Python + Flask を利用して REST API サーバーを作成します。

なお、リソースの保存先には SQLite を利用しています。SQLite の詳細は以下の記事をご覧ください。

pip3 install flask
vim app.py
from flask import Flask, g, request                                                                                               
import sqlite3
import json   
              
dbpath = 'test.db' #テーブルを保存するファイル
app = Flask(__name__)
              
def get_db():#データベースのコネクションを取得
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(dbpath)
        db.execute('CREATE TABLE IF NOT EXISTS tweets_tbl(id INTEGER PRIMARY KEY AUTOINCREMENT, tweet VARCHAR(140))')
    return db 
              
@app.route('/tweet', methods=['GET'])
def get_tweet():
    con = get_db() #コネクションを取得
    con.row_factory = sqlite3.Row #カラム名取得のため
    cur = con.cursor() #カーソル取得
              
    cur.execute('SELECT * FROM tweets_tbl')
    tweets = []
    for row in cur.fetchall(): #sqlite3.Row オブジェクトを dict に変換
        tweets.append(dict(row))
              
    return json.dumps(tweets,indent=2)
              
@app.route('/tweet', methods=['POST'])
def post_tweet():
    con = get_db() #コネクション
    cur = con.cursor() #カーソルインスタンスを作成
              
    tweet = request.json["tweet"] #POSTメソッド のデータを取得
    cur.execute(f"INSERT INTO tweets_tbl(tweet) values('{tweet}')") #ツイート文をテーブルにINSERT
    con.commit()
              
    return 'Success a Tweet!\n'
              
@app.route('/tweet/<id>', methods=['PUT'])
def put_tweet(id):
    con = get_db() #コネクション
    cur = con.cursor() #カーソルインスタンスを作成
              
    tweet = request.json["tweet"]
    cur.execute(f"UPDATE tweets_tbl SET tweet = '{tweet}' WHERE id = {id}")
    con.commit()
              
    return 'Update a Tweet!\n'
              
@app.route('/tweet/<id>', methods=['DELETE'])
def delete_tweet(id):
    con = get_db() #コネクション
    cur = con.cursor() #カーソルインスタンスを作成
    cur.execute(f"DELETE FROM tweets_tbl WHERE id = {id}")
    con.commit()
              
    return 'Delete a Tweet!\n'
              
if __name__ == "__main__":
    app.run() 
flask run

REST API クライアントの使い方

今回クライアントとして、以下の2種類を紹介します。

curl をクライアントに利用

ここでは curl を利用して API リクエストを行います。

POST メソッドでツイートを投稿
curl localhost:5000/tweet -XPOST -H "Content-Type: application/json" -d '
{
  "tweet": "Hello World!"
}'
Success a Tweet!
GET メソッドでツイートを取得
curl localhost:5000/tweet -XGET
[
  {
    "id": 1,
    "tweet": "Hello World!"
  }
]
PUT メソッドでツイートを更新
curl localhost:5000/tweet/1 -XPUT -H "Content-Type: application/json" -d '
{
  "tweet":"Change World"
}'
Update a Tweet!
curl localhost:5000/tweet -XGET
[
  {
    "id": 1,
    "tweet": "Change World"
  }
]
DELETE メソッドでツイートを削除
curl localhost:5000/tweet/1 -XDELETE
Delete a Tweet!
curl localhost:5000/tweet -XGET
[]

Python の requests をクライアントに利用

ここでは、Python の requests ライブラリを利用して API リクエストを行います。

POST メソッドでツイートを投稿
vim post_api.py
import requests
import json
 
url = 'http://localhost:5000/tweet'
headers = {'Content-Type': 'application/json'}
data = {"tweet": "Hello World!"}

res = requests.post(url, headers=headers ,data=json.dumps(data))
print(res.text)
python3 post_api.py
Success a Tweet!
GET メソッドでツイートを取得
vim get_api.py
import requests

url = 'http://localhost:5000/tweet'
res = requests.get(url)
print(res.text)
python3 get_api.py
[
  {
    "id": 1,
    "tweet": "Hello World!"
  }
]
PUT メソッドでツイートを更新
vim put_api.py
import requests
import json
 
url = 'http://localhost:5000/tweet/1'
headers = {'Content-Type': 'application/json'}
data = {"tweet": "Change World!"}                                                
 
res = requests.put(url, headers=headers ,data=json.dumps(data))
print(res.text)
python3 put_api.py
Update a Tweet!
python3 get_api.py
[
  {
    "id": 1,
    "tweet": "Change World!"
  }
]
DELETE メソッドでツイートを削除
vim delete_api.py
import requests
import json
 
url = 'http://localhost:5000/tweet/1'
 
res = requests.delete(url)
print(res.text)
python3 delete_api.py
Delete a Tweet!
python3 get_api.py
[]

REST API の認可・認証

REST API の認証認可には OAuth 2.0OpenID Connect (OIDC) を利用します。

用語の意味や具体的な実装方法については以下の記事をご覧ください。

認証・認可周りの基本用語

OAuth 2.0

OpenID Connect (OIDC)

SSO (シングルサインオン)


関連記事

Web サーバー構築