【個人開発】DTOの設計とREST APIの戻り値で1日悩んだ話
個人開発の中で、DTO(Data Transfer Object)の設計とREST APIの戻り値設計に悩んだので、備忘録も兼ねてまとめました。
初心者なりに「セキュアなAPIとは?」「DTOの分割基準って?」「戻り値の設計ってどうしてる?」と考えていたら、あっという間に一日が過ぎてしまいました…。
同じような悩みを持っている方の参考になったり、逆にアドバイスをいただけたら嬉しいです。
今回の事象
- やりたかったこと:Userの「ステータス」「パスワード」「メールアドレス」などを変更できるAPIを作りたい
-
最初にやったこと:
UserPutRequest
のようなDTOを作って、それで全部まとめて変更しようとした - 引っかかったこと:名前があいまい(意図が伝わりにくい)+ セキュリティが心配
DTOの命名と責任分離について悩んだこと
-
UserStatusChangeRequest
みたいな名前にしても、「結局それって何が変わるの?」が曖昧だった - パスワードを変更するときに「旧パスワードなし」で置き換わってしまうのはまずい
- メールアドレスも変更時は本人確認的なもの(=パスワード)を入れないと不安
セキュアなAPI設計に向けた工夫
-- パスワード変更時
SELECT password FROM users WHERE email = 'xxx@yyy.com';
-- 旧パスワードと突き合わせ
-- OKなら
UPDATE users SET password = 'newHashedPassword' WHERE email = 'xxx@yyy.com';
パスワード変更
UserPasswordChangeRequest
email
oldPassword
newPassword
メールアドレス変更
UserEmailChangeRequest
currentEmail
newEmail
password
REST APIの戻り値問題にも直面
POST, PUT, PATCH の戻り値って何がベスト?
-
200 OK
で何も返さない? - 更新されたデータを返す?
- 独自メッセージを返す?
迷走した末の結論
ステータスコード+メッセージを enum
で管理する
共通クラス ApiStatus
を作成 することに。
- 更新されたデータ返す?
- 独自メッセージ返す?
迷走した末に、ステータスコード+メッセージを enum で管理する共通クラスを作成することに。
作ってみた Enum クラス(抜粋)
public enum ApiStatus {
OK(200, "OK"),
CREATED(201, "Created"),
NO_CONTENT(204, "No Content"),
FORBIDDEN(403, "Forbidden"),
NOT_FOUND(404, "Not Found"),
METHOD_NOT_ALLOWED(405, "Method Not Allowed"),
CONFLICT(409, "Conflict"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error");
private final int status;
private final String message;
ApiStatus(int status, String message) {
this.status = status;
this.message = message;
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
}
→ 各レスポンス DTO で statusCode
, message
として共通で使えるように。
感想とまとめ
クラス設計や命名、セキュリティを考え出すと、ほんと一日すぐ消し飛ぶ…。
でも、「どう作るか?」を考えるのが 一番楽しい部分 だと改めて実感しました。
ChatGPTとあーだこーだ話しながら設計を詰めるのも、なかなか面白いです(時々暴走しますが笑)
最後に
まだまだ新米なので、こうした方がいいよ!というアドバイスがあれば、ぜひコメントで教えてください!