My coworker and I are debating the correct design for an API. Say we have a function void deleteBlogPost(int postId)
. What should this function do if the blog post indexed with postId
does not exist?
I believe it would be appropriate to throw an exception, because the function should be designed to do one thing. When the user calls a function called deleteBlogPost
, they always expect the post with ID postId
to be deleted. To try to delete a post with an invalid postId
does not make sense, so an exception should be thrown.
My colleague argues that the caller does not really intend to delete a specific post, just to ensure that after the call, the post does not exist. If you call deleteBlogPost
with a nonexistent post ID, the goal state is already achieved, so nothing should happen. He also noted that this design ensures calls to deleteBlogPost
are idempotent, but I'm not convinced that this is a good thing.
We found examples of both patterns in several APIs. For instance, compare deleting a dictionary/map entry with a key that does not exist between Python and Java:
Python:
my_dict = {}
del my_dict['test'] # KeyError: 'test'
Java:
Map<String, Object> map = new HashMap<>();
map.remove("test"); // no exception thrown
Should a function throw exceptions based on its expected behavior or its goal state?
ensureNotExists()
.deleteBlogPost
would need to be named something likeensureBlogPostIsDeleted
. Your also wrong because its actually not an exceptional circumstance for a blog post id to not have an existent blog post. It is an actual and legitimate scenario. Therefore the function should return that the blog post did not exist, when the id did not have a blog post.try/catch
, then I would go with "do nothing for non existing id".