Mongoose not returning HTTP status code 204 on delete - mongodb

I am using mongoose for mongodb and trying to delete a record. A standard REST API should return in a 204 response on delete. However mongoose is returning 200
return await ppc.deleteOne({ _id: id });
With response having deletedCount
data:
deletedCount: 1
status: 200
or using
return await ppc.findOneAndRemove({ _id: id});
returns same 200 with body. Is there any delete API which returns 204 by default?
Like in spring boot or spring data rest it returns 204 by default for a successful delete request. I understand if I need body in response I would need to send 200 for a proper REST API convention. However if I need to return the 204 myself with mongoose, mongo db I would need to check for deletedCount first ,which I can do either on backend or frontend which is a little extra work. I wanted to ensure is there some setting or some other API which defaults it to 204?
Issue with 200 status code is that mongoose even return 200 for a ID which doesn't exists.

You should separate the function of Mongodb as a database vs the HTTP response code your app returns, there is no relation between the two.
200 is the default "success" response code as it's returned because your app successfully executes the code with no errors. mongoose or mongodb are not the ones returning the status.
What it sounds like you want to be doing is incorporate some basic logic into your routes, like so:
const delResult = await ppc.deleteOne({ _id: id });
response.json({statusCode: 402, ...delResult})
With mongoose you can also prebuild triggers to execute after certain operations to handle this type of custom logic for you, that's how you avoid code duplication throughout your app.

Related

Correct REST API Response HTTP Status Code

I am creating a REST API which will run a simple database query and return some data, based on the payload.
If my SQL query returns no results then I am returning the plain text "No Records Found".
What HTTP response code would be appropriate for such an event. Is it 200 or 404.
If you are returning a JSON payload and your resource can be represented as a collection, then it makes sense to return 200 along with an empty array ([]) in the response payload.
If you are returning a single resource for a given identifier, and no resource can be found with the given identifier, then it makes sense to return 404.

REST principles - returning a simple response

I'm working with Django REST framework. By default, all the requests returns a JSON object containing the pagination (prev, next, count, results). This is useful in 90% of the cases where the user retrieves or creates info about something. However, there are a few resources which don't have to return anything but rather a confirmation that everything went smoothly - for example, imagine a resource which is just a heartbeat request ("ping") to maintain the session active.
Would it be okay to return a simple response, such as {result: true} (without any pagination like the rest of resources have) or would this be an eventual violation of the REST principles?
If all you want is to know if the URI is fully serviceable, disregarding the body completely, you should simply support a HEAD request instead of GET.
Yes, ouf course such a response to a ping request is OK. Pagination is something only suitable for a collection that can be paged. Paging An unique resource that is not a collection does not make sense.
For the ping request you could even leave the response body empty.
Request:
GET /ping
Response:
200 OK
Content-Length: 0
Pagination should be solved with range headers or hyperlinks. You don't need the body in empty responses, just the status header.

RESTful POST request, If the record already exists on POST data, do we return 200 OK or 304 Not Modified?

I have a POST request endpoint, where user repeatedly post the data. Before I insert the data to database, based on user request,I do check if the record already exists.
- If record already exists, I return 200 OK with response body containing the table_id and status
- If record does not exists, I create new record and return 200 OK with response body containing table_id and status
Basically in both the cases, user get status 200. As user it might be confusing as one couldn't be able to distinguish whether its a new record or existing record.
I thought I would return 304 with response body and inform the consumer telling that This request is "Not Modified", in this way consumers would make a decision.
Is it a good practice or is there alternative approach in RESTful principals.
304 is intended to be used only for a Conditional GET response, to indicate that the requested content has not changed since the last time the client asked for it. It is not appropriate for a POST response.
For a POST response, use 201 if a new record is created, otherwise use 200 or maybe 409 instead.
See the following for some helpful tips in designing REST APIs:
Using HTTP 304 in response to POST
HTTP response code for POST when resource already exists
Creating an efficient REST API with HTTP
REST lesson learned: Avoid 204 responses
304 Not Modified is to be used when HTTP caching headers are in play, so this doesn't apply to your case.
I would use 422 Unprocessable Entity that is for validation errors, when the request is well-formed but there are semantic errors.
And if the record did not previously exist, you should answer with 201 Created (rather than 200 OK) that is the standard response to a successful resource creation (following a POST creation request).

find-or-create idiom in REST API design?

say we have a 'user' resource with unique constraint on 'name'. how would you design a REST API to handle a find-or-create (by name) use case? I see the following options:
option 1: multiple requests
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //or something else
client:
GET /user?name=bob
server:
HTTP 200 //returns existing user
option 2: one request, two response codes
client:
POST /user
{"name":"bob"}
server:
HTTP 200 //returns existing user
(in case user is actually created, return HTTP 201 instead)
option 3: request errs but response data contains conflicting entity
client:
POST /user
{"name":"bob"}
server:
HTTP 409 //as in option1, since no CREATE took place
{"id": 1, "name":"bob"} //existing user returned
I believe the "correct" RESTful way to do this would be :
GET /user?name=bob
200: entity contains user
404: entity does not exist, so
POST /user { "name" : "bob" }
303: GET /user?name=bob
200: entity contains user
I'm also a big fan of the Post-Redirect-Get pattern, which would entail the server sending a redirect to the client with the uri of the newly created user. Your response in the POST case would then have the entity in its body with a status code of 200.
This does mean either 1 or 3 round-trips to the server. The big advantage of PRG is protecting the client from rePOSTing when a page reload occurs, but you should read more about it to decide if it's right for you.
If this is too much back-and-forth with the server, you can do option 2. This is not strictly RESTful by my reading of https://www.rfc-editor.org/rfc/rfc2616#section-9.5:
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
If you're okay with veering away from the standard, and you're concerned about round-trips, then Option 2 is reasonable.
I am using a version of option 2. I return 201 when the resource is created, and 303 ("see other") when it is merely retrieved. I chose to do this, in part, because get_or_create doesn't seem to be a common REST idiom, and 303 is a slightly unusual response code.
I would go with Option 2 for two reasons:
First, HTTP response code, 2xx (e.g. 200 nd 201) refers to a successful operation unlike 4xx. So in both cases when find or create occurs you have a successful operation.
Second, Option 1 doubles the number of requests to the server which can be a performance hit for heavy load.
I believe a GET request which either:
returns an existing record; or
creates a new record and returns it
is the most efficient approach as discussed in my answer here: Creating user record / profile for first time sign in
It is irrelevant that the server needs to create the record before returning it in the response as explained by #Cormac Mulhall and #Blake Mitchell in REST Lazy Reference Create GET or POST?
This is also explained in Section 9.1.1 of the HTTP specification:
Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

REST status code 204 on paginated result

I am designing a REST like API for paginated data retrieval of a YUI-based client.
The REST URL looks like this for a GET request:
/app/catalog/data?startIndex=<int>&results=<int>&sort=<sting>&dir=<string>
All parameters are optional, i.e. if no parameters are given, all data from DB will be dumped.
Now say that there are only 1000 records in the database. Following reqeust is made:
/app/catalog/data?startIndex=1100&results=25
What status code should I return if the paginated result from the database remains empty though the request was fine?! I can't decide whether this is 204 or 404.
The produced media types are JSON and CSV.
I would say 204 is most appropriate. The request was successful, just with no results.
10.2.5 204 No Content
The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.
Sounds exactly like the case.
I can't decide whether this is 204 or 404.
Neither. Just return 200 with an empty result (empty XML document or JSON array, whatever you use). Typically I use REST services with paginated views so along with results page I return total number of records. This will help clients to realize the mistake. But technically it is nothing wrong.
Use 204 for DELETE operations (there's really no content to return) and for PUT.
BTW (bold mine):
if no parameters are given, all data from DB will be dumped
Believe, you don't want to do this...
What format do you normally return your results in? I'd be inclined to make this 204 or even 200 returning an empty list.
HTTP 204 in pagination response is not factible because of the payload. When paginating you should return pagination information like, items returned, total items, offset, etc. which makes no sense with HTTP 204.
HTTP 204 is useful on resource updates (ie PUT) when you want to explicitly say that the resource does not need to be fetched again (GET). For example, resources that have calculated fields and require a refresh of the view after every update, fetching those calculated fields from the server. Therefore, the 204 status code has specific use cases and must be designed and documented.
I would use one of:
HTTP 200 with count=0 and no items in the returned list.
HTTP 400 because invoker asked for an url that is invalid
HTTP 404 because items to return are not found
Choose the one that best suits the way your API works.
I think it's safe to return an error (4xx + error info) in this situation because the offset can be exceeded by one of these assumptions:
A coding error
Invoker is not fetching data from begining (no fresh state)
Invoker ignored pagination data (present on each response)
You are not using total field in the response (which is optional because there are some situations where you can not count all items or simply it's very expensive counting them). In this case, if your last page has the same number of items (count) as the number of items asked for in the request (limit), there is no way to know that this is the last page, so you try another one. In that last request you will get a count=0 in the response and you can stop asking for pages. This case makes it fair to return a 200 code also because the programmer did exactly what you asked for in the API documentation.