TypeScript Express tutorial #15. Using PUT vs PATCH in MongoDB with Mongoose

Express JavaScript TypeScript

This entry is part 15 of 15 in the TypeScript Express tutorial

When we develop a REST API, we have a set of HTTP methods that we can choose. An important thing to understand is that HTTP methods are, to a large extent, indicators of actions. Therefore, it is our job to make them work properly. In theory, not much stops us, for example, from deleting entities with the GET method. By caring about keeping conventions, we improve the readability of our API and make it predictable.

Most of the HTTP methods are rather straightforward. Although, in Mongoose with Express, PUT and PATCH methods might cause some misinterpretation. In this article, we compare them both and inspect how to implement them both in MongoDB with Mongoose.

This series of articles results in this repository. Feel free to give it a star.

PUT

The PUT method is in the HTTP protocol for quite a while now. Its main responsibility is to modify an existing entity.

The most important thing about PUT is that it replaces an entity. If we don’t include a property that an entity contains, it should be removed

As you can see above, the post contains quite a few properties. Let’s send an example of a PUT request:

As you can see, we’ve changed the   property. We’ve also included all other fields, such as the   and the  . Let’s send another PUT request:

This request should remove all of the other properties and leave only  .

Using PUT with MongoDB and Mongoose

The above is not precisely the case with MongoDB and Mongoose. It does not let us remove or change the  .

To implement a proper PUT with MongoDB and Mongoose, we need a way to replace a document instead of updating it. One of the most commonly used ways to modify an entity are   and  . Unfortunately, their default behavior is not to replace the document, but perform a partial update on it. Therefore, if we don’t pass a property, it does not remove it from the entity.

One way to achieve the desired behavior is to use the   method. As the name suggests, it replaces the whole document – just what we need.

The result of the   method contains the    property that describes the number of documents matching our filter. If none were found, we could assume that an entity with a given id does not exist.

Unfortunately, the result does not contain the modified document, so we would need to look it up using the   function to send it back.

The above difficulties might be solved using the   function. Unfortunately, the   package lacks the TypeScript definition of the   method.

There were some efforts made to add it, though. If it is ever finalized, I will update this article.

Although the documentation currently does not mention that, we can also pass the   option to   and  . Thanks to that, it will replace a whole document instead of performing a partial update.

Creating new entities with PUT

The specification also mentions that we could use PUT to create a new entity if the desired one wasn’t found. We refer to this behavior as an upsert.

Mongoose supports it by allowing us to pass the upsert option to the   query.

If there is an element in the   array, we look for an entity with a new id. Otherwise, we use the identifier provided by the user.

PATCH

The PUT method might not always be the best choice for updating entities. It assumes that users know all of the details of a particular entity, but this is not always the case. A solution to that might be the PATCH method.

PATCH was introduced to the HTTP protocol in 2010 within RFC 5789. It aims to apply a partial modification to a resource. We should treat PATCH as a set of instructions on how to modify a resource.

The most straightforward way to implement a handler for a PATCH method is to expect a body with a partial entity.

The above should modify the entity with new  . As opposed to PUT, we should not remove the rest of the properties.

Using PATCH with MongoDB and Mongoose

The  method is very much fitting to implement the PATCH method. We mention it in the second part of this series.

Thanks to passing the   option, our query results in an updated version of the entity. Thanks to that, we can send it back in the response effortlessly.

If in the data passed to the   function, we include a different  , Mongoose throws an error.

If we want to remove properties when performing a PATCH with  , we would have to send null explicitly.

JSON Patch

Another approach to implementing the PATCH method is to literally send a set of instructions on how to modify a resource. You can use the JSON Patch format that defines an array of patch operations.

We can find the documentation on the JSON Patch format here. There is also the fast-json-patch utility that might help you create and read such patches.

Summary

In this article, we’ve gone through possible ways to implement the update functionality. When choosing between PUT and PATCH, we need to consider what is the best choice in your particular case. No matter what we decide on, once we decide on one of the approaches, we need to code them properly. When doing so, we need to consider how are the PATCH and PUT methods defined in the specification and implement them accordingly.

Series Navigation<< TypeScript Express tutorial #14. Code optimization with Mongoose Lean Queries
Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Antonio Martos Harres
2 years ago

Hello, first of all, thank you for the article! It is AWESOME and even mitigates NoSQL injections.
However, when I was implementing PUT on my backend, I found that if I pass no IDs into put, it fails, if I pass {} or {_id: ”}
So I decided to make a small check, if (!id), it runs create repository in the same class