HTTP code when deleting records - ruby-on-rails

I am using Ruby on Rails and I am trying to understand all the subtleties of HTTP codes to bring my app with standards, and I'm facing the following case.
Let's say I have a database with two tables, Companies and Employees.
If users try to delete a company with no employee, it is deleted and server sends code 200.
If users try to delete a company with employees, it is not deleted and server sends a message ("There are employees linked to this company..."). In this case, what code does server have to send ? I was thinking of HTTP 4XX but in my opinion, it is not a client error.

Use the 409 Conflict error code. It indicates that the request could not be processed because of conflict in the request.
Once the employees are gone then the conflict is removed and the delete will work. You can think of it as a client error in the sense that it is a conflicted request from the client.

If the client is not allowed to use the DELETE method on companies with employees, I would suggest 405 Method not allowed. Include an explanation of why in the response body.

Related

Can one differentiate cases when returning an HTTP 422 in a REST API?

I am developing a REST API in Rails.
The API returns an HTTP 422 unprocessable entity with error messages when model validations fail.
However, a model can have several validations and I want to delegate the translation of the error messages to the API consumer and that is why it needs to differentiate what was the specific cause for the server to return a 422.
I was thinking about using subcodes, just like Facebook does in its API. Is there a way to do this keeping the REST practices?
Also, what does one do when an error 422 occurs for multiple causes at the same time?
RFC 7231
Client Error 4.x.x
Except when responding to a HEAD request, the server SHOULD send a representation containing an explanation of the error situation, and whether it is a temporary or permanent condition.
Normally, you should encode information that is specific to your domain in the message-body of the response. The status line and response headers are there for generic components (browsers, caches, proxies) to have a coarse understanding of what is going on.
The Problem Details specification lays out the concern rather well.
consider a response that indicates that the client's account doesn't have enough credit. The 403 Forbidden status code might be deemed most appropriate to use, as it will inform HTTP generic software (such as client libraries, caches, and proxies) of the general semantics of the response.
However, that doesn't give the API client enough information about why the request was forbidden, the applicable account balance, or how to correct the problem. If these details are included in the response body in a machine-readable format, the client can treat it appropriately; for example, triggering a transfer of more credit into the account.
I don't promise that Problem Details is well suited for your purposes; but as prior art it should help you to recognize that the information you want to communicate belongs in the body of the response, with a suitable Content-Type header to inform the consumers which processing logic they need to use.

Office365 API Error "Mailbox database change detected;"

Occasionally when sending an email through the Office365 API, we get an error back:
excerpt:
{"httpCode":503,"headers":"HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 503
Service UnavailableX-MS-Diagnostics: Routing Validation; Mailbox
database change detected; moved from database 31f16b42-8c32-43a3-a05f-
f554bb4c579f to 78f2e7a1-e65f-4148-8be4-b98ac0635fdf\r\nX-
BEServerRoutingError: Mailbox database change detected; moved from
database 31f16b42-8c32-43a3-a05f-f554bb4c579f to 78f2e7a1-e65f-4148-
8be4-b98ac0635fdf"}
Does anyone know why this happens,its annoying when the client thinks your app is faulty, when its actually an error within the Office API which causes it.
You just made a call in the middle of a re-balancing operation. Just retry your call. For things like this, you shouldn't need to show them to the client.

Is List Joined Teams API Working

Working with Teams preview API and attempting to get all of the Teams of which the current person is a member. I don't get any authorization errors, but instead get a 400 - Bad Request as a response. Bad Request is a REALLY strange error for a GET request with no parameters, i.e. we're just asking for https://graph.microsoft.com/beta/me/joinedTeams using the access token we just got from Azure AD.
Is this just not working right now? Or is there something maybe missing from the documentation? Or something else?
Update 2/27/18: this has been fixed.
It's an active bug we are tracking.

When should I use HttpDelete or HttpPut in an asp.net mvc application

I use always HttpGet or HttpPost even when my action is executing a delete method on the database.
For what should I use then HttpDelete/HttpPut ?
Web browsers only support GET and POST, so if you are building a web site, there is no need for PUT or DELETE. If you are building a RESTful api, though, PUT and DELETE are the way to go if you want your users to be able to put and/or delete stuff.
EDIT: It seems browsers do support DELETE and PUT in their implementations of XMLHttpRequest. Hence you can use them in ajax requests. Html forms, though, do not support them.
If you build an OData service.
HTTP DELETE - Deletes the entity data that the specified resource represents. A payload is not present in the request or response messages.
HTTP PUT - Replaces existing entity data at the requested resource with new data that is supplied in the payload of the request message. (msdn)
There's a presentation with Scott Hanselman that might be interesting. (I haven't seen it yet.)
There's also a couple of lectures on pluralsight on OData if you have a subscription there.
I guess you have understood about the use of DELETE request but PUT is a little different thing.
If I'm creating a new resource in the server and if the URI through which it can be accessed is decided by me then I'll go for PUT. In most of the cases the URI is decided by the server and hence POST go for creation and PUT usually for update.
Final thing is, like GET both DELETE and PUT are idempotent, means how many times the client send the requests serially the state of the server should be changed to same as in the first request.

Client Server API pattern in REST (unreliable network use case)

Let's assume we have a client/server interaction happening over unreliable network (packet drop). A client is calling server's RESTful api (over http over tcp):
issuing a POST to http://server.com/products
server is creating an object of "product" resource (persists it to a database, etc)
server is returning 201 Created with a Location header of "http://server.com/products/12345"
! TCP packet containing an http response gets dropped and eventually this leads to a tcp connection reset
I see the following problem: the client will never get an ID of a newly created resource yet the server will have a resource created.
Questions: Is this application level behavior or should framework take care of that? How should a web framework (and Rails in particular) handle a situation like that? Are there any articles/whitepapers on REST for this topic?
The client will receive an error when the server does not respond to the POST. The client would then normally re-issue the request as they assume that it has failed. Off the top of my head I can think of two approaches to this problem.
One is that the client can generate some kind of request identifier, such as a guid, which it includes in the request. If the server receives a POST request with a duplicate GUID then it can refuse it.
The other approach is to PUT instead of POST to create. If you cannot get the client to generate the URI then you can ask the server to provide a new URI with a GET and then do a PUT to that URI.
If you search for something like "make POST idempotent" you will probably find a bunch of other suggestions on how to do this.
If it isn't reasonable for duplicate resources to be created (e.g. products with identical titles, descriptions, etc.), then unique identifiers can be generated on the server which can be tracked against created resources to prevent duplicate requests from being processed. Unlike Darrel's suggestion of generating unique IDs on the client, this would also prevent separate users from creating duplicate resources (which you may or may not find desirable). Clients will be able to distinguish between "created" responses and "duplicate" responses by their response codes (201 and 303 respectively, in my example below).
Pseudocode for generating such an identifier — in this case, a hash of a canonical representation of the request:
func product_POST
// the canonical representation need not contain every field in
// the request, just those which contribute to its "identity"
tags = join sorted request.tags
canonical = join [request.name, request.maker, tags, request.desc]
id = hash canonical
if id in products
http303 products[id]
else
products[id] = create_product_from request
http201 products[id]
end
end
This ID may or may not be part of the created resources' URIs. Personally, I'd be inclined to track them separately — at the cost of an extra lookup table — if the URIs were going to be exposed to users, as hashes tend to be ugly and difficult for humans to remember.
In many cases, it also makes sense to "expire" these unique hashes after some time. For example, if you were to make a money transfer API, a user transferring the same amount of money to the same person a few minutes apart probably indicates that the client never received the "success" response. If a user transfers the same amount of money to the same person once a month, on the other hand, they're probably paying their rent. ;-)
The problem as you describe it boils down to avoiding what are called double-adds. As mentioned by others, you need to make your posts idempotent.
This can be easily implemented at the framework level. The framework can keep a cache of completed responses. The requests have to have a request unique so that any retries are treated as such, and not as new requests.
If the successful response gets lost on its way to the client, the client will retry with the same request unique, the server will then respond with its cached response.
You are left with durability of the cache, how long to keep responses, etc. One approach is to remove responses from the server cache after a given period of time, this will depend on your app domain and traffic and can be left as a configurable step on the framework piece. Another approach is to force the client to sent acknowledgements. The acks can be sent either as separate requests (note that these could be lost too), or as extra data piggy backed on real requests.
Although what I suggest is similar to what others suggest, I strongly encourage you to keep this layer of network resiliency to do only that, deal with drop requests/responses and not allow it to deal with duplicate resources from separate requests which is an application level task. Merging both pieces will mush all functionality and will not leave you with a clear separation of responsibilities.
Not an easy problem, but if you keep it clean you can make your app much more resilient to bad networks without introducing too much complexity.
And for some related experiences by others go here.
Good luck.
As the other responders have pointed out, the basic problem here is that the standard HTTP POST method is not idempotent like the other methods. There is an effort underway to establish a standard for an idempotent POST method known as Post-Once-Exactly, or POE.
Now I'm not saying that this is a perfect solution for everybody in the situation you describe, but if it is the case that you are writing both the server and the client, you may be able to leverage some of the ideas from POE. The draft is here: https://datatracker.ietf.org/doc/html/draft-nottingham-http-poe-00
It isn't a perfect solution, which is probably why it hasn't really taken off in the six years since the draft was submitted. Some of the problems, and some clever alternate options are discussed here:
http://tech.groups.yahoo.com/group/rest-discuss/message/7646
HTTP is a stateless protocol, meaning the server can't open an HTTP connection. All connections get initialized by the client. So you can't solve such an error on the server side.
The only solution I can think of: If you know, which client created the product, you can supply it the products it created, if it pulls that information. If the client never contacts you again, you won't be able to transmit information about the new product.

Resources