Rest API Response Error Code for when a related resource has a blocked state - rest

Which 400-level response code is most appropriate when a user that has permission to POST a target resource, but one of the dependent resources' status causes the target resource not to be created.
Example:
Entity1
id: 'A',
status: 'BLOCKED'
Entity2:
id: 'B'
LinkEntity:
entity1Id: 'A'
entity2Id: 'B'
Result when POSTing LinkedEntity: 'Error: Cannot link to Entity1 because it is BLOCKED'
Which Response Code is best to use in this case?

The 409 (Conflict) status code indicates that the request could not be completed due to a conflict with the current state of the target resource.

It sounds like a permission-related issue. For this case 403 Forbidden is probably best.

Related

What does the MarkLogic out of the box rest api return when deleting a document fails?

The MarkLogic documentation gives information for a success response, but no information for a failed delete.
https://docs.marklogic.com/REST/DELETE/v1/documents
I would expect a 404 if the document doesn't exist, a 410 if it's already been deleted, or a 403 if I don't have authorization to delete the document.
From my limited testing, it seems I get a 204 if the document doesn't exist, and a 400 if I'm not authorized.
Some REST practioners assert the DELETE request should be idempotent. So long as the document doesn't exist after the operation finishes, the operation succeeded.
That said, recent versions of the REST API allow a check parameter on document delete requests. If check is set to "exists," the operation should throw an error if the document doesn't exist.
In passing, I don't see how the 404 and 410 cases could be distinguished, given that there's no operational state on the server.
Hoping that helps,
You could take an API-first approach and build your own great REST APIs directly on MarkLogic where you take full control over the URI Path as well as response codes and anything else for that matter with XQRS.
declare
%rest:DELETE
%rest:path("/db/{$uri=.*}")
%xdmp:update
function delete-doc($uri as xs:string) {
if(fn:doc-available($uri)) then (
xdmp:document-delete($uri),
<rest:response>
<http:response status="410" message="Gone"/>
</rest:response>
)
else (
<rest:response>
<http:response status="404" message="Not Found"/>
</rest:response>
)
};

REST API Error code after POSTing resource with invalid FK

I'm designing a REST API which has a Banner resource that's related to another two resources: Placeholder and Page.
While the relationship with Placeholder can be null, a Banner must be related to a Page. The business rules define that Pages are always created independently. Then, for new Banner resources, the page does always exist and the page's id can be passed as a parameter. The same applies for the Placeholder, although this could null.
So, I decided that a Banner resource can be also created independently (instead of a nested resource) as follows:
POST https://api.example.com/banners
{
"name": "banner's name",
"page": "PAGE_ID",
"placeholder": "PLACEHOLDER_ID",
... other parameters
}
What error code should be returned by the API when provided page or placeholder does not exist?
I'm returning a HTTP 404, but it feels odd. I thought about 409, but this doesn't look like a conflict.
PD: If I used a nested URL as POST /pages/<page_id>/banners, the 404 makes sense for a non existent page, but it still have the same problem for placeholder.
Assuming that you want to create a banner resource using POST /banners and that banner resource has
a required page attribute which value must be an existing PAGE_ID
an optional placeholder attribute which value must be an existing PLACEHOLDER_ID
and a name and other properties which I assume must also be controlled
Returning a 404 on post /banners is not a good idea
The consumer may provide from none to all invalid properties. Following your idea that would give something like that:
If only page is invalid you would return a 404
If only placeholder is invalid you would return a 404
If page and placeholder are both invalid you would have to return a 404 indicating that both value are invalid
If other properties are invalid, you would probably return a 400 Bad Request.
If page and/or placeholder and some other properties are invalid, which status return? a 404 or 400?
It's a bit complex and inconsistent and therefore not really usable for the API's consumer.
A 400 Bad Request is a better solution for post /banners
The best way to handle this use case is to consider all possible errors in the provided resources as a basic Client Error and therefore use 400 Bad Request status. The body of the response will contain a description of each error for each invalid property.
But there's a cleaner solution with POST /pages/page_id/placeholders/placeholder_id/banners
The POST /pages/<page_id>/banners is almost a good idea, you only need to push it further.
It seems that a banner goes into a placeholder which is in a page. If it's true you can do a POST /pages/<page_id>/placeholders/<placeholder_id>/banners to create a banner.
If page_id is invalid you return a 404 (indicating 'page not found')
If page_id is valid but placeholder_id is invalid you return a 404 (indicating 'place holder not found')
If page_id and placeholder_id are valid but property in the banner is invalid you return a 400 Bad Request (indicating which values are invalid)

Getting information on ride requests in sandbox mode

Using Uber's API, I managed to make a trip request, and then change it's status to accepted via the PUT command described in the docs.
However, if afterwards I make a GET request to fetch ride's attributes, I get status = accepted, but driver, eta, location and vehicle are null. Thus, I can't test that the whole flow works.
Am I missing something?
Actually, once the trip in sandbox mode is set to status "Accepted" you should be able to see all those attributes. I just tested this myself and it worked fine.
The flow I followed was:
1) POST to https://sandbox-api.uber.com/v1/requests (with the proper params and auth headers) to create a sandbox trip
2) PUT to https://sandbox-api.uber.com/v1/sandbox/requests/{trip_UUID from step 1) with JSON body: {"status": "accepted"}
3) GET https://sandbox-api.uber.com/v1/requests/current OR GET https://sandbox-api.uber.com/v1/requests/{trip_UUID from step 1}
Could you provide some more details on the exact flow you followed?
According to the /v1/requests/{request_id} endpoint documentation
Note: The following fields are populated only when a trip is active:
driver
vehicle
pickup
destination
The meaning of the "accepted" status is:
accepted The Request has been accepted by a driver and is "en route"
to the start location (i.e. start_latitude and start_longitude).
I think by "trip is active" they mean the request status needs to be in_progress
in_progress The Request is "en route" from the start location to the
end location.
Try to change the status of the request to in_progress using the PUT /v1/sandbox/requests/{request_id} sandbox endpoint.
After this you should be able to get access to the driver, vehicle, pickup and destination fields.

HTTP POST response Location header when creating multiple resources

The HTTP/1.1 standard states that if a POST operation results in the creation of a resource, then the response should include a Location header with the address of the new resource.
If a resource has been created on the origin server, the response
SHOULD be 201 (Created) and contain an entity which describes the
status of the request and refers to the new resource, and a Location
header (see section 14.30).
and in section 14.30,
For 201 (Created) responses, the Location is that of the new resource
which was created by the request.
Now suppose that my API allows batch creation of resources by POSTing an array to the collection resource URL. For example:
POST /books
[
{
"name": "The Colour of Magic",
"published": "1983"
},
{
"name": "The Light Fantastic",
"published": "1986"
}
]
Since two \book\{bookId} resources have been created, what should be the value of the Location header in this case?
The question Http post response after multiple new resource creation? is similar, but it asks about the response entity, not the headers (and is unanswered).
RFC 2616 is obsolete. Stop looking at it except for historical purposes.
The current spec, RFC 7231, says:
"If one or more resources has been created on the origin server as a result of successfully processing a POST request, the origin server SHOULD send a 201 (Created) response containing a Location header field that provides an identifier for the primary resource created (Section 7.1.2) and a representation that describes the status of the request while referring to the new resource(s)." -- http://greenbytes.de/tech/webdav/rfc7231.html#POST
And yes, that doesn't help a lot when there isn't a "primary" resource.
I know this answer is late to the party but I believe the best solution is to create a new "Batches" resource with a uuid identifier that would return the list of Book URLs that were added using a URL like this:
http://api.example.com/batches/{uuid}
e.g.
http://api.example.com/batches/2b9b251f71a4b2901d66e04725bc0c9cb5843c74
Then your POST or PUT can return the above URL on it's Location: {url} header and a 201 - Created status code.
If you then GET that URL that resource should respond with a representation that lists the URLs created in that batch, as well as any other info about the batch such as its uuid and the time/date it was created.
{
"uuid": "2b9b251f71a4b2901d66e04725bc0c9cb5843c74",
"datetime": "2005-08-15T15:52:01+00:00",
"books": [
"http://api.example.com/books/the-colour-of-magic",
"http://api.example.com/books/the-light-fantastic"
]
}
Those resources could then have a TTL of an hour or a month, whatever you choose. Or they could live forever if you want; whatever your use-case requires.
I think that you are in a particular use case for the header Location. In the case of bulk creation, the result of the processing is generally provided within the returned content itself. As a matter of fact, the processing can be completely or partially successful. I mean all elements were added or only a subset and the result shows to the end-user what actually happens.
So I think that the header Location isn't usable in such context. I see two options for the status code:
The status code is 201 if at least one element is created)
The status code is 200 to tell that the bulk request globally succeeds but the result of each operation is described in the response content.
You can however notice that a status code 202 exists if your resource handles the bulk creations in an asynchronous way. But in the context, you need then to pull a resource to get the status of the inserts.
Regarding the content of the response, you are free to choose. We could imagine something like that:
{
"took": 4,
"errors": true | false,
"items": [
{ "added": true,
"error": null
"id": "123"
},
{ "added": false,
"error": {
"code": "err12",
"description": "validation error (field type, ...)"
}
"id": null
}
]
}
ElasticSearch provides such bulk api with create but also update and delete support - see this link for more details: http://www.elastic.co/guide/en/elasticsearch/guide/current/bulk.html.
Here are similar questions that could give some hints:
How to Update a REST Resource Collection
REST API - Bulk Create or Update in single request
Hope it helps you,
Thierry

How to handle nested resources in Web API ("REST") when not found?

Let say I have a resource Person and on a person I have a nested resource SomeResource. Which status code should be returned and why in the following scenarios?
/Person/1/SomeResource (SomeResource does not exist)
/Person/1/SomeResource (Person does not exist)
I think that 404 should be used in both scenarios but not everyone agrees and I would like to know why. You could argue that Person is the underlying resource and SomeResource is just a "property" on that resource and the request to SomeResource should therefor return nothing in the first scenario but 404 in the second scenario. I think that might be an option, but I still like 404 more. Another scenario that I don't like at all is to return 500 with an error description, that was an alternative I heard in the discussion as well but that forces the consumer to program against exception which I don't like. 500 for me means that something went wrong and you can't really do anything about it.
The problem is that the argument was that you don't know why you got a 404 if you got it, was it because of that the Person didn't exist or because of that the SomeResource didn't exist.
UPDATE 1:
Maybe I should break out SomeResource to a separate resource like
/SomeResource/1
which returns a response like {data: {the data}, person: {person data}}, and this only returns 404 if both are missing but if the data is missing a 200 is returned with empty data.
UPDATE 2:
I think I figured out which status code to use and it is 400 for when the person is not existing since I at that point considering it a request you should never have done, that is, a bad request. When SomeResource is missing I would go for 404 since the Person did exist but the nested resource was missing.
It may be helpful to remember that a given URI is intended to identify at single "resource". Semantically, a URI structure does not support the concept of "nested" resources. It seems you have two resources: Person & SomeResource in your scenario where SomeResource has a relation of some sort with Person. You could try a structure like this to represent this relationship:
GET /person/1
{
name: "Some Value",
someResource: {
"Href": "http://yourSite.com/someresource/123",
"Title": "Get some resource for this specific person"
},
// other key/value pairs as appropriate...
}
This way you are not overloading the 400 & 404 with application specific meanings. If the client has received a valid Person result, it would simply invoke the SomeResource href and would receive the appropriate 404 or not depending on SomeResource 123 existing. If the Person URI does not exists, invoking it would appropriately return 404 since it does not exist.