【初心者向けハンズオン】REST APIの解説とRESTの思想に則ったコード作成
みなさんこんにちは。iidahです。
アイソルートに入社してもうすぐ1年。
今年から新規の案件の中で、REST APIを用いた開発を行っていくことになりました。
REST APIの特徴、設計方法を学習したので本記事ではその内容を記載しています。
REST APIの仕組み、設計方法について知りたいという方は、是非ご一読ください!
目次
この記事の目的
本記事では、REST APIの特徴や、Pythonを用いたREST APIの設計方法についてまとめています。
これらの内容を通じて、REST APIを初めて利用する方に向けたハンズオンの一助になればと思い、本記事を執筆しました。
REST APIの特徴
REST APIとは「REST」という設計思想に則ったAPI通信を行う方法です。
RESTとは「REpresentational State Transfer」の略であり、一般的には後述する4つの原則からなるWebサービスの設計思想といわれています。
①ステートレス性
ステートレス性とは、サーバーとクライアントが通信を行う際にクライアントの情報を保持しないという考え方です。
つまり、REST APIでは複数回通信を行う場合でも、前の通信の情報を保持せずに各通信が独立した通信となります。
サーバー側でクライアントの情報を保持しないので、スケーラブルなサーバーを設計することができます。
②アドレサビリティ
REST APIではhttps://api.twitter.com/2のようにURL(URI)にリクエストを投げ、レスポンスを受け取ることで通信します。
このURLが1つのリソースと紐づく考え方がアドレサビリティになります。
以下の図のように、異なるリソースに対して操作を行う場合は、異なるURLに対しリクエストを投げ、レスポンスを受け取る形式になります。
逆に同じリソースに異なる操作を行う場合は、同じURLに対しリクエストを投げます。

③インターフェースの統一
インターフェースの統一とは、リソースに対しCRUDの操作を行うときに、各操作に対応したメソッドを利用する考え方です。
例えばHTTPを用いてAPI通信(CRUD操作)を行う場合は、以下のようなインターフェースを利用することができます。
| C(作成) | POSTメソッド |
| R(参照) | GETメソッド |
| U(更新) | PUTメソッド |
| D(削除) | DELETEメソッド |
④接続性
最後は接続性です。接続性とはAPIで受け取った情報の中に別リソースへのリンクを入れることができるという考え方です。
例えば以下の図のようにAPI(https://example.com/item)で商品一覧を取得した際に、その下の表のように商品の詳細(contents)をURLとして一緒に受け取ることができるような考え方が接続性になります。

Response
| item_id | item_name | Price | contents |
| 1 | apple | 1000 | https://example.com/1/contents |
| 2 | orange | 1400 | https://example.com/2/contents |
| 3 | banana | 2000 | https://example.com/3/contents |
| 4 | peach | 30000 | https://example.com/4/contents |
| 5 | melon | 500 | https://example.com/5/contents |
以上4つが「REST」の設計思想になります。
これらの設計思想に則り、APIを設計していくと、REST APIによる通信が可能になります。
【ハンズオン】REST APIによる通信
次に、上記で解説したREST APIの設計思想をもとに、WebサーバとクライアントのPythonコードを作成し、実際に通信していく様子を見ていきます。
・サーバ側のコード(server.py)
・クライアント側のコード(client.py)
・サーバに保存するデータ(item_data.txt、user_data.txt)
これらのserver.pyとclient.pyを利用し以下のAPI通信を行います。
| RESTの設計思想 | API通信 |
| ①ステートレス性 | 同じURL(http://localhost:8000/user)に2回アクセス |
| ②アドレサビリティ | 異なるURL(http://localhost:8000/user、http://localhost:8000/items)にそれぞれアクセス |
| ③インターフェースの統一 | http://localhost:8000/itemsに対し、CRUDの操作を行う |
| ④接続性 | APIのレスポンスからさらにURL(https://example.com)を取得 |
http://localhost:8000は今回立てるWebサーバのURLです。
環境情報
環境情報は以下になります。ライブラリのインポートについては後述しています。
| OSバージョン | Windows11 |
| 言語バージョン | Python 3.10.0 |
| 使用ライブラリ | fastapi , pydantic , requests |
ディレクトリ構造は以下のようになります。
to_restapi/
∟app_api/
∟server.py
∟item_data.txt
∟user_data.txt
∟client.py
サーバー側のコード
最初にAPI通信を受け取るサーバを作成します。以降は単に「サーバ」と記載します。
こちらも同様に、利用するモジュールをインストールします。
$ pip install fastapi
$ pip install pydantic
fastapiはPythonで利用できるWebフレームワークです。クライアントからのリクエストを受けるための受け口の作成と作成先のサーバの作成に利用します。
pydanticはPythonでデータのバリデーションを行うためのライブラリです。今回はクライアント側から受け取るデータの形式の定義に利用しています。
サーバのコードは以下のようになります。
#server.py
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi import Response
app = FastAPI() #FastAPIのインスタンスを作成
class Item(BaseModel): #POSTメソッドで受け取るデータのモデルを定義
item_id: int
name: str
price: float
p_date : str
link: str = None # linkフィールドをオプションに設定
class User(BaseModel):
name:str
age:int
email:str
@app.get("/user")#GETメソッドでアクセスしたときの処理
def get_users():
with open("user_data.txt", "r") as f: # テキストファイルからデータを読み込み
users = f.readlines()
return {"users": users}
@app.get("/item") #GETメソッドでアクセスしたときの処理
def root():
with open("item_data.txt", "r") as f: # テキストファイルからデータを読み込み
items = []
#for文で1行ずつ読み込む場合
for line in f:
print(line.strip())
item = {
"item_id": line.split(",")[0],
"name": line.split(",")[1],
"price": line.split(",")[2],
"p_date": line.split(",")[3],
"link": line.split(",")[4].strip()
}
items.append(item)
return {"items": items}
@app.post("/items/") #POSTメソッドでアクセスしたときの処理
def create_item(item: Item, res:Response):
with open("item_data.txt", "a") as f: # 受け取ったデータをテキストファイルに保存
f.write(f"\n{item.item_id}, {item.name}, {item.price}, {item.p_date}, {item.link}")
return {"item_name": item.name, "item_price": item.price, "purchase_date": item.p_date, "link": item.link}
@app.put("/items/{item_id}") #PUTメソッドでアクセスしたときの処理
def update_item(item_id: int, item: Item):
lines = []
print(f"Updating item_id: {item_id}")
with open("item_data.txt", "r") as f:
lines = f.readlines()
line_sum = sum(1 for line in lines if line.strip())
if item_id < 0 or item_id > line_sum:
return {"error": "Item not found lines is "+str(line_sum)} #エラーハンドリング
lines[item_id -1] = f"{item.item_id}, {item.name}, {item.price}, {item.p_date}, {item.link}\n"
with open("item_data.txt", "w") as f:
f.writelines(lines)
return {"item_id": item_id, "item_name": item.name, "item_price": item.price, "purchase_date": item.p_date, "link": item.link}
@app.delete("/items/{item_id}") #DELETEメソッドでアクセスしたときの処理
def delete_item(item_id: int):
with open("item_data.txt", "r") as f:
lines = f.readlines()
if item_id < 0 or item_id > len(lines):
return {"error": "Item not found"} #エラーハンドリング
deleted_line = lines.pop(item_id -1)
print(f"Deleted item: {deleted_line.strip()}")
with open("item_data.txt", "w") as f:#ファイルの内容を上書き
f.writelines(lines)
return {"deleted_item": deleted_line.strip()}
GET リクエストでは、対応するテキストファイルの内容をそのまま返します。
POST リクエストでは、リクエストの Body 部分に含まれるデータ(item)をテキストファイルに追記し、書き込んだデータをレスポンスとして返します。
PUT リクエストでは、http://localhost:8000/items/7 のように URL の末尾に item_id を指定し、その ID に対応する行のデータを書き換えます。
書き換え後の内容をレスポンスとして返します。
DELETE リクエストでは、PUT リクエストと同様に item_id を指定し、該当する行をテキストファイルから削除します。
削除したデータをレスポンスとして返します。
これらのレスポンスの結果を確認することで、APIの通信を確認していきます。
クライアント側のコード
続いて、サーバへアクセスするためのクライアント側のコードを作成します。
まずはコードで利用するモジュールをインストールします。
$ pip install requests
requestsはHTTPを用いてWebサーバへアクセスするためのモジュールです。
このモジュールでWebサーバ(server.pyを実行してできるWebサーバ)にリクエストを投げます。
クライアント側のコードは以下になります。
#client.py
import requests
from datetime import datetime as dt
post_data = {
"item_id": 7,
"name": "j"
,"price": 61000
,"p_date": str(dt.now())
}
putdata = {
"item_id": 7,
"name": "j_updated",
"price": 62000,
"p_date": str(dt.now()),
"link": "https://example.com"
}
access_url = "http://localhost:8000/" #アクセスするリソースに対しURLが対応する
print("ステートレス性を確認するため、複数回アクセス")
responce_user1 = requests.get(access_url + "user")
print(responce_user1.text)
responce_user2 = requests.get(access_url + "user")
print(responce_user2.text)
print("アドレサビリティを確認するため、特定リソースにアクセス")
responce_user_detail = requests.get(access_url + "user")
print(responce_user_detail.text)
response_item_detail = requests.get(access_url + "item")
print(response_item_detail.text)
print("インターフェースの統一性を確認するため、CRUD操作を実行")
responce_item = requests.post(access_url + "items/", json=post_data)
print(responce_item.text)
responce_item = requests.get(access_url + "item")
print(responce_item.text)
responce_item = requests.put(access_url + "items/7", json=putdata)
print(responce_item.text)
responce_item = requests.delete(access_url + "items/7")
print(responce_item.text)
print("接続性を確認するため、body内のリンク情報を取得")
responce_item = requests.get(access_url + "item")
for item in responce_item.json()["items"]:
if item["link"] != 'None':
print(item)
http://localhost:8000/ は、自分のPC上で起動しているローカル Web サーバにアクセスするためのURLです。
localhost は自分のPCを指し、:8000 はそのサーバが待ち受けているポート番号を表します。
今回はこのローカルのWebサーバに対しAPI通信を行います。
サーバに保存するデータ
今回はテキストファイルにサーバのデータの保存、追加を行い、API通信で参照します。
以下のテキストファイルを用意してください。
item_data.txt
1, a, 33000.0, 2026-01-26 23:30:56.754718, https://example.com
2, b, 34000.0, 2026-01-26 23:32:46.950408, None
3, c, 35000.0, 2026-01-26 23:35:27.682663, None
4, d, 36000.0, 2026-01-26 23:51:43.089996, None
5, e, 37000.0, 2026-01-26 23:52:45.218192, None
6, f, 38000.0, 2026-01-26 23:54:40.088490, None
user_data.txt
user1, 10, user1@example.com
user2, 11, user2@example.com
user3, 15, user3@example.com
コードの実行
次に各コードを実行します。
まずはサーバを起動します。以下のコマンドを実行してください。
$ uvicorn main:app --reload
実行すると以下のような表示が出ます。
$ uvicorn running on http://127.0.0.1:8000
これにより「http://127.0.0.1:8000」つまり「http://localhost:8000」にアクセスすることでWebサーバにアクセスすることができるようになります。
では、起動したサーバにhttpのリクエストを送ってみます。
以下のコマンドでclient.pyを実行してください。
$ python client.py
すると以下のような結果が得られます。
ステートレス性を確認するため、複数回アクセス
{"users":["user1, 10, user1@example.com\n","user2, 11, user2@example.com\n","user3, 15, user3@example.com\n"]}
{"users":["user1, 10, user1@example.com\n","user2, 11, user2@example.com\n","user3, 15, user3@example.com\n"]}
アドレサビリティを確認するため、特定リソースにアクセス
{"users":["user1, 10, user1@example.com\n","user2, 11, user2@example.com\n","user3, 15, user3@example.com\n"]}
{"items":[{"item_id":"1","name":" a","price":" 33000.0","p_date":" 2026-01-26 23:30:56.754718","link":"https://example.com"},{"item_id":"2","name":" b","price":" 34000.0","p_date":" 2026-01-26 23:32:46.950408","link":"None"},{"item_id":"3","name":" c","price":" 35000.0","p_date":" 2026-01-26 23:35:27.682663","link":"None"},{"item_id":"4","name":" d","price":" 36000.0","p_date":" 2026-01-26 23:51:43.089996","link":"None"},{"item_id":"5","name":" e","price":" 37000.0","p_date":" 2026-01-26 23:52:45.218192","link":"None"},{"item_id":"6","name":" f","price":" 38000.0","p_date":" 2026-01-26 23:54:40.088490","link":"None"}]}
インターフェースの統一性を確認するため、CRUD操作を実行
{"item_name":"j","item_price":61000.0,"purchase_date":"2026-02-01 23:58:04.551783","link":null}
{"items":[{"item_id":"1","name":" a","price":" 33000.0","p_date":" 2026-01-26 23:30:56.754718","link":"https://example.com"},{"item_id":"2","name":" b","price":" 34000.0","p_date":" 2026-01-26 23:32:46.950408","link":"None"},{"item_id":"3","name":" c","price":" 35000.0","p_date":" 2026-01-26 23:35:27.682663","link":"None"},{"item_id":"4","name":" d","price":" 36000.0","p_date":" 2026-01-26 23:51:43.089996","link":"None"},{"item_id":"5","name":" e","price":" 37000.0","p_date":" 2026-01-26 23:52:45.218192","link":"None"},{"item_id":"6","name":" f","price":" 38000.0","p_date":" 2026-01-26 23:54:40.088490","link":"None"},{"item_id":"7","name":" j","price":" 61000.0","p_date":" 2026-02-01 23:58:04.551783","link":"None"}]}
{"item_id":7,"item_name":"j_updated","item_price":62000.0,"purchase_date":"2026-02-01 23:58:04.551783","link":"https://example.com"}
{"deleted_item":"7, j_updated, 62000.0, 2026-02-01 23:58:04.551783, https://example.com"}
接続性を確認するため、body内のリンク情報を取得
{'item_id': '1', 'name': ' a', 'price': ' 33000.0', 'p_date': ' 2026-01-26 23:30:56.754718', 'link': 'https://example.com'}
ステートレス性の確認では、複数回アクセスしても同じ出力が得られていることが分かります。
アドレサビリティの確認では、各リソースに対してアクセスした結果が適切に返されています。
インターフェースの統一性の確認では、CRUD 操作に対応したレスポンスがそれぞれ取得できています。
接続性の確認では、レスポンスの body 内に含まれる URL 情報を取得できています。
以上より、各設計思想に則った通信が正しく行われていることを確認できます。
終わりに
本記事ではREST APIの特徴、Pythonを用いたREST APIの設計方法について説明しました、
本記事を通じて、REST APIを初めて利用する人のハンズオンの1つになればと思います。
各コードはコピーアンドペーストして利用できるので、ぜひ試してみてください。









