Python | テスト・設計・品質:API 設計

Python Python
スポンサーリンク

API設計って何?一言でいうと「他人(未来の自分)が使いやすい“入口”を設計すること」

ここでいう「API」は、Web API だけじゃなく、
「関数・クラス・モジュールの“使い方の顔”」も含めた広い意味での API だと思ってください。

Python で言えば、

どんな関数名・引数名にするか
どんな戻り値にするか
例外をどう扱うか
どんな単位でモジュールを分けるか

こういった「外から見えるインターフェース」をどう設計するかが、API設計です。

重要なのは、「使う側の気持ち」で考えることです。
書く側の都合ではなく、「こう書けたら気持ちいいよね」という視点で形を決めていきます。


まずは「使いにくいAPI」と「使いやすいAPI」を比べてみる

使いにくい関数の例

次のような関数を考えてみます。

def do_user(a, b, c, d=False, e=None):
    # a: name, b: email, c: age
    # d: send_mail, e: logger
    ...
Python

一見すると「何でもできそう」ですが、使う側からするとかなりつらいです。

何が必須で、何がオプションなのか分かりにくい。
a, b, c が何を意味しているのか、毎回コメントを見ないと分からない。
d が True のときに何が起きるのか、コードを読まないと分からない。

こういう API は、「一度書いた本人しか分からない」状態になりがちです。

使いやすい関数にリファクタリングしてみる

同じ処理を、API設計を意識して書き直してみます。

from dataclasses import dataclass
from typing import Protocol

@dataclass
class UserInput:
    name: str
    email: str
    age: int

class MailSender(Protocol):
    def send_welcome(self, email: str) -> None:
        ...

def register_user(
    data: UserInput,
    mail_sender: MailSender | None = None,
) -> None:
    ...
Python

ここでは、次のようなことを意識しています。

引数に意味のある名前を付ける。
関連する値は一つのオブジェクト(UserInput)にまとめる。
「メールを送るかどうか」というフラグではなく、「送る手段(MailSender)」を渡す。

使う側のコードは、かなり読みやすくなります。

input_data = UserInput(name="Taro", email="taro@example.com", age=20)
register_user(input_data)
Python

「何をしているか」が、コードを見ただけで分かるようになります。
これが API設計の第一歩です。


良いAPI設計の軸その1:名前と引数で「意図」が伝わること

関数名は「何をするか」をそのまま書く

関数名は、コメントの代わりです。
「何をする関数なのか」が、名前だけで分かるのが理想です。

例えば、

processhandle のようなふわっとした名前より、
register_usersend_reset_mail のように、具体的な動詞+対象の方が、使う側の理解が早くなります。

Python では、動詞+名詞をスネークケースで書くのが定番です。

create_order
cancel_order
calculate_total

こういう名前は、それだけで「何をするか」が伝わります。

引数名は「何を渡せばいいか」が分かるようにする

引数名も同じです。

a, b, c ではなく、
name, email, age のように、意味が分かる名前にします。

さらに、型ヒントを付けると、より安心感が増します。

def register_user(name: str, email: str, age: int) -> None:
    ...
Python

これだけで、「この関数は名前・メール・年齢を受け取るんだな」と分かります。


良いAPI設計の軸その2:戻り値と例外の扱いを「一貫させる」

成功・失敗をどう表現するかを決める

API設計でよく迷うのが、「失敗したときどうするか」です。

戻り値で True / False を返すのか。
例外を投げるのか。
エラーコードを返すのか。

大事なのは、「一貫性」です。
同じモジュールの中で、似たような関数がバラバラのルールを持っていると、使う側が混乱します。

例えば、「ユーザー登録系の関数は、失敗したら例外を投げる」と決めたなら、
そのモジュール内ではそれを徹底します。

class UserAlreadyExistsError(Exception):
    ...

def register_user(data: UserInput) -> None:
    if exists_user(data.email):
        raise UserAlreadyExistsError
    ...
Python

使う側は、「例外で失敗を知る」と分かっているので、こう書けます。

try:
    register_user(input_data)
except UserAlreadyExistsError:
    print("すでに登録されています")
Python

「成功したら True、失敗したら False、たまに例外」みたいな API は、
使う側にとって地雷原です。

None を返すか、例外を投げるか

例えば、「ユーザーをIDで検索する」関数を考えます。

def find_user(user_id: int) -> User | None:
    ...
Python

見つからないときに None を返すのか、
UserNotFoundError を投げるのか。

ここも、「どう使われるか」を考えて決めます。

「見つからないことが普通にありうる」なら、None を返すのが自然です。
「見つからないのは異常事態」なら、例外の方が自然です。

どちらにしても、APIとして「どちらの方針か」を揃えることが大事です。


良いAPI設計の軸その3:呼び出し側のコードが「読みやすいか」を最優先する

呼び出し側から逆算して設計する

API設計で一番強い考え方は、「先に呼び出し側を書く」です。

例えば、「ユーザー登録API」を作りたいとき、
まずは理想の呼び出しコードを書いてみます。

client = UserApiClient(base_url="https://example.com")
user = client.register(name="Taro", email="taro@example.com")
print(user.id)
Python

こう書けたら気持ちいいな、という形を先に決めてしまう。
そのあとで、「この形を実現するには、中身をどう作ればいいか」を考えます。

関数やクラスの設計を、「中身から」ではなく「使い方から」考える。
これが API設計の本質です。

「引数が多すぎる」と感じたら、オブジェクトにまとめる

呼び出し側のコードを見ていて、
引数が多すぎて読みづらいと感じたら、それは API の改善ポイントです。

例えば、

register_user(
    name="Taro",
    email="taro@example.com",
    age=20,
    address="Tokyo",
    phone="000-0000-0000",
    send_mail=True,
    send_sms=False,
)
Python

のように増えてきたら、
「ユーザー登録リクエスト」というオブジェクトにまとめた方が読みやすくなります。

@dataclass
class RegisterUserRequest:
    name: str
    email: str
    age: int
    address: str
    phone: str
    send_mail: bool = True
    send_sms: bool = False

def register_user(req: RegisterUserRequest) -> User:
    ...
Python

呼び出し側はこうなります。

req = RegisterUserRequest(
    name="Taro",
    email="taro@example.com",
    age=20,
    address="Tokyo",
    phone="000-0000-0000",
)
user = register_user(req)
Python

「何を渡しているか」が一目で分かるようになります。


Web APIとしてのAPI設計も、考え方は同じ

エンドポイントの設計も「使う側の目線」で考える

Web API(HTTP の API)も、本質は同じです。
「クライアントから見て、分かりやすく・一貫性があるか」が大事です。

例えば、ユーザー関連の API を考えます。

POST /users でユーザーを作る。
GET /users/{id} でユーザーを取得する。
PATCH /users/{id} でユーザー情報を更新する。

こういう「動詞+名詞」の組み合わせを、REST ではよく使います。

レスポンスの JSON も、Python のドメインモデルと対応させると分かりやすくなります。

{
  "id": 1,
  "name": "Taro",
  "email": "taro@example.com"
}

これを Python 側では User クラスとして扱う。
Web API の設計と、Python の API設計は、実はかなり地続きです。


API設計とテスト・品質の関係

良いAPIは「テストしやすい」

APIがきれいに設計されていると、テストも自然と書きやすくなります。

例えば、さっきの register_user のように、

入力を一つのオブジェクトにまとめる
外部依存(メール送信など)はインターフェースで受け取る

という形にしておくと、テストはこう書けます。

class DummyMailSender:
    def __init__(self) -> None:
        self.sent_to: list[str] = []

    def send_welcome(self, email: str) -> None:
        self.sent_to.append(email)

def test_register_user_sends_mail():
    mailer = DummyMailSender()
    data = UserInput(name="Taro", email="taro@example.com", age=20)

    register_user(data, mail_sender=mailer)

    assert mailer.sent_to == ["taro@example.com"]
Python

APIが「きれいに分かれている」ほど、
テスト対象を小さく切り出せます。

逆に、APIがごちゃごちゃしていると、
テストもごちゃごちゃして、壊れやすくなります。

良いAPIは「変更に強い」

API設計をちゃんとしておくと、
内部の実装を変えても、外から見える形を変えずに済むことが増えます。

例えば、UserApiClient の内部実装を、

requests から httpx に変える
同期処理から非同期処理に変える

といった変更をしても、
client.register(name=..., email=...) という API を変えなければ、
呼び出し側のコードはそのまま動きます。

API設計は、「外から見える約束」を決めることです。
その約束を守り続ける限り、中身は好きなだけ改善できます。
これが品質と開発速度の両方に効いてきます。


初心者がAPI設計を練習するときのおすすめのやり方

先に「理想の呼び出しコード」を書いてみる

何か機能を作るとき、
いきなり中身を書き始めるのではなく、
まずは「こう使えたらいいな」という呼び出し側を書いてみてください。

例えば、Todo アプリなら、

todo = TodoService()
todo.add("買い物に行く")
for item in todo.list():
    print(item.title)
Python

のように、「こう書けたら気持ちいい」という形を先に決める。
それを実現するために、クラスや関数の設計を考える。

この練習を繰り返すと、自然と API設計の感覚が育っていきます。

「このAPIを初めて見る人は、迷わず使えるか?」と自問する

自分の書いた関数やクラスを見て、
こう自分に問いかけてみてください。

名前だけ見て、何をするか分かるか。
引数名と型ヒントだけ見て、何を渡せばいいか分かるか。
戻り値と例外のルールが、一貫しているか。

ここで「うーん…」と感じたら、
それは API設計を見直すチャンスです。


まとめ(API設計は「使う側の気持ちで形を決める」設計の技術)

初心者目線でまとめると、API設計はこういうものです。

API設計は、関数・クラス・モジュール、そしてWeb APIなどの「外から見える顔」を、使う側の目線で分かりやすく・一貫性を持って設計すること。
名前・引数・戻り値・例外の扱いを丁寧に決めることで、呼び出し側のコードが読みやすくなり、テストしやすくなり、内部実装を変えても壊れにくい「強い約束」を作れる。
練習としては、「先に理想の呼び出しコードを書く」「初めて見る人が迷わず使えるかを自問する」といった小さな習慣から始めると、API設計のセンスがじわじわ育っていく。

タイトルとURLをコピーしました