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 ベースのエンドポイントで「リソース」を決める (
https://api.twitter.com/
) - HTTP メソッドで、リソースの「操作」を決める (GET, POST, PUT, DELETE)
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ツイートを削除 |
次に 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 API | REST API の機能 |
---|---|
GET /tweet | ツイートを取得 |
POST /tweet | ツイートを投稿 |
PUT /tweet/:id | 指定した ID のツイートを更新 |
DELETE /tweet/:id | 指定した ID のツイートを削除 |
REST API サーバーを作成
Python + Flask を利用して REST API サーバーを作成します。
なお、リソースの保存先には SQLite を利用しています。SQLite の詳細は以下の記事をご覧ください。
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()
REST API クライアントの使い方
今回クライアントとして、以下の2種類を紹介します。
curl をクライアントに利用
ここでは curl を利用して API リクエストを行います。
POST メソッドでツイートを投稿
Success a Tweet!
GET メソッドでツイートを取得
[
{
"id": 1,
"tweet": "Hello World!"
}
]
PUT メソッドでツイートを更新
Update a Tweet!
[
{
"id": 1,
"tweet": "Change World"
}
]
DELETE メソッドでツイートを削除
Delete a Tweet!
[]
Python の requests をクライアントに利用
ここでは、Python の requests ライブラリを利用して API リクエストを行います。
POST メソッドでツイートを投稿
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)
Success a Tweet!
GET メソッドでツイートを取得
[
{
"id": 1,
"tweet": "Hello World!"
}
]
PUT メソッドでツイートを更新
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)
Update a Tweet!
[
{
"id": 1,
"tweet": "Change World!"
}
]
DELETE メソッドでツイートを削除
import requests
import json
url = 'http://localhost:5000/tweet/1'
res = requests.delete(url)
print(res.text)
Delete a Tweet!
[]
REST API の認可・認証
REST API の認証・認可には OAuth 2.0 や OpenID Connect (OIDC) を利用します。
用語の意味や具体的な実装方法については以下の記事をご覧ください。