はじめに
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を公開してもクライアント側から使うことができなければ意味がなくなってしまいますので注意が必要です。