はじめに
PUTとPOSTの区別がつき、概ね認識が間違ってなさそうなことが分かりました。
そこでひっそりと登場してきたのがPATCH。
気がついた以上見逃すわけにはいかない。というわけで、これまで書いてきたコードを見直してみます。
MongoDBのドキュメントの更新処理を見直す
見直し対象のコード
ドキュメントの更新処理で利用するコードです。
指定のドキュメントのtitle末尾に(更新)をつける処理です。これは果たしてPUTで良いのかどうか?
router.put(Book.self, at:"api/book") { (req, book) -> Future<HTTPStatus> in
let client = try! req.make(MongoClient.self)
let collection = client.db("vaporapp").collection("books", withType: Book.self)
return try req.content.decode(Book.self).map(to: HTTPStatus.self) { book in
let query: Document = try Document.init(fromJSON: "{\"title\":\"" + book.title + "\"}")
let updatedBook: Document = try Document.init(fromJSON: "{\"$set\": {\"title\":\"" + book.title + "(更新)\"" + "}}")
_ = try! collection.updateMany(filter: query, update: updatedBook)
return .ok
}
}返り値が.okなのは見逃してくださいお代官様。
HTTPメソッドの意味合いから考えると、これはPATCHではないでしょうか。
書き直してみる
早速書き直してみます。
router.patch(Book.self, at:"api/book") { (req, book) -> Future<HTTPStatus> in
let client = try! req.make(MongoClient.self)
let collection = client.db("vaporapp").collection("books", withType: Book.self)
return try req.content.decode(Book.self).map(to: HTTPStatus.self) { book in
let query: Document = try Document.init(fromJSON: "{\"title\":\"" + book.title + "\"}")
let updatedBook: Document = try Document.init(fromJSON: "{\";$set\": {\"title\":\"" + book.title + "(更新)\"" + "}}")
_ = try! collection.updateMany(filter: query, update: updatedBook)
return .ok
}
}PUTがPATCHに変わっただけで、中身はそのまま。
ではPUTはどうなるの?
router.put(Book.self, at:"api/book") { (req, book) -> Future<HTTPStatus> in
let client = try! req.make(MongoClient.self)
let collection = client.db("vaporapp").collection("books", withType: Book.self)
return try req.content.decode(Book.self).map(to: HTTPStatus.self) { book in
let query: Document = try Document.init(fromJSON: "{\"title\":\"" + book.title + "\"}")
_ = try! collection.replaceOne(filter: query, replacement: book)
return .ok
}
}元々のコードを生かした状態で書き換えたのでクエリに若干の無理がありますが、replaceOneでドキュメントを置き換えています。
PUTは指定したURIに紐づくドキュメントを扱うものなので、router.put(Book.self, at:"api/book")の形ではなく、router.put("api/book",String.parameter)でドキュメントを特定できるパラメータを渡してクエリを組むのが良さそうです。更新ドキュメントはリクエストボディに詰め込んでおきましょう。
いずれにせよ、PUTならばreplaceOne、PATCHならばupdateManyまたはupdateOne、と対応付けておくと良さそうです。
まとめ
PUTとPATCHの違いを意識して見直してみました。PUTでも部分的な更新をすることができるので、ここまでこだわる必要があるかどうかというところですが、HTTPメソッドの正しい(と思う)使い方を目指してみるという点ではこだわってみるのも良いかもしれません。
メジャーどころの御三家GET、POST、DELETEに比べると、影の薄さは否めません。でも、メソッドとして存在するからにはちゃんと理解して使ってみたいですよね。
補足
PATCHはRFCに現れたり消えたりしていた経緯があるようです。確かに、PUTとPATCHを明確に区別する必要もなさそうな気もします。そもそもPUTで事足りてしまったためにそこまで利用する人が居なかったということだったのかもしれません。
また、クライアントアプリケーション側がPATCHに対応していない可能性があります。こだわりのAPIを公開してもクライアント側から使うことができなければ意味がなくなってしまいますので注意が必要です。




