【入門】REST API の解説と Flask + Python で設計・実装

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
関連記事:サーバー
スポンサーリンク

例: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 の場合は該当する API が無い※
(ツイートを置き換え [=上書き] する機能は無い)
DELETEリソースを削除DELETE https://api.twitter.com/2/tweets/:id
ツイートを削除
※2022/12/01 時点

次に 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 (シングルサインオン)

関連記事