Can PUT request change the URL? - api

My application with a HTTP API provides some resources that are identified by name. So, the URLs are constructed as the following:
/path/to/resources/<name>
For example:
/path/to/resources/my_resource
The resources can be updated with PUT operations. It is also allowed to rename a resource with such an update.
PUT /path/to/resources/my_resource
{"name": "new_name", <other properties>}
Response:
HTTP/1.1 204 No content
As a result, the updated resource is now accessible under a new URL:
GET /path/to/resources/new_name
Response:
HTTP/1.1 200 OK
{"name": "new_name", <other properties>}
The old URL is no longer valid:
GET /path/to/resources/my_resource
Response:
HTTP/1.1 404 Not found
Is such behavior correct? Should the PUT operation return the Location header with a new URL? Is it OK to return the Location header with the 204 No content status?
After writing this question I found another, quite similar: REST API Design : Is it ok to change the resource identifier during a PUT call?
The accepted answer was that it is allowed, but not recommended. Still don't know what about the Location header, though.

By changing a resource identifier, I understand you are deleting a resource and creating a new one. So, the approach you described in the question is basically a delete operation using the wrong HTTP verb.
According to the RFC 7231, the current reference for HTTP/1.1, PUT requests are used to create or replace a resource:
4.3.4. PUT
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload.
[...]
If the target resource does not have a current representation and the
PUT successfully creates one, then the origin server MUST inform the
user agent by sending a 201 (Created) response. If the target
resource does have a current representation and that representation
is successfully modified in accordance with the state of the enclosed
representation, then the origin server MUST send either a 200 (OK) or
a 204 (No Content) response to indicate successful completion of the
request.
[...]
I would do the following when the resource identifier needs to be changed:
Perform a DELETE in the existing resource. The response would be a 204 indicating the request was fulfilled.
Perform a POST or PUT to create the resource using the new identifier. The response would be a 201 indicating the resource was created. The response would contain a Location header indicating where the resource is located.
To replace the state of the target resource (keeping the resource identifier), perform a PUT and return a 204 to indicate the operation succeeded.
I don't know about your requirements, but I wouldn't allow the user to change or create the identifier of a resource. I would assume the resource identifier is immutable and should be generated by the application (UUID, of example) or an identifier generated by the database.

I agree with Cássio Mazzochi Molin's answer. However the question is theoretical one, whether renaming the resource really changes the 'identity' of a resource.
For example if a person's name changes, that does not change who the person is. I still would like the URI I previously got for the "same" person to work, even after the name change.
So I guess my point is not to include non-identity related information into the URI. Include an Id number or similar content-unrelated information.
Don't do a DELETE and PUT to another URI (don't relocate the resource) if the identity of the object did not change.

Related

attributes.headers getting lost after a http Request call in Mulesoft?

I am getting some attributes in an API but all getting lost after an HTTP request connector in mule4.
why is it happening?
Look in the connector's configuration properties -> advanced tab for the connector configuration (in this case the HTTP connector's "request" operation) and you'll find a target variable and target value. If you fill in the target with a name - this does an enrichment to avoid overwriting the Mule message. If you leave it blank (the default) it will save the message (attributes, payload) over the top of the existing one - which is what you're seeing now. This mirrors the old mule 3 functionality, but sometimes you want it to leave what you have there alone.
So for the target value you get to pick exactly what gets saved.. If you want just payload: put that in. If you want both payload and attributes - I'd use "message" as that will mean you get both payload and attributes saved in the variable. Of course you may not want as much saved, so feel free to put in whatever dataweave expression you like - so you could even create something with bits from anywhere like:
{
statusCode: attributes.statusCode,
headers: attributes.headers,
payload: payload
}
A connector operation may replace the attributes with those of the operation. If you need to preserve the previous attributes you need to save them to a variable.
This is a default behaviour of MuleSoft. Whenever request crosses to transport barrier it losses existing attributes. You need to preserve attribute before HTTP Request.

Http status code when data not found in Database

I'm trying to understand which Http Status Code to use in the following use case
The user tries to do a GET on an endpoint with an input ID.
The requested data is not available in the database.
Should the service send back:
404 - Not Found
As the data is NOT FOUND in the database
400 - Bad Request
As the data in the input request is not valid or present in the db
200 - OK with null response
200 - OK with an error message
In this case we can use a standard error message, with a contract that spans across all the 200 OK responses (like below).
BaseResponse {
Errors [{
Message: "Data Not Found"
}],
Response: null
}
Which is the right (or standard) approach to follow?
Thanks in advance.
Which is the right (or standard) approach to follow?
If you are following the REST API Architecture, you should follow these guidelines:
400 The request could not be understood by the server due to incorrect syntax. The client SHOULD NOT repeat the request without modifications.
It means that you received a bad request data, like an ID in alphanumeric format when you want only numeric IDs. Typically it refers to bad input formats or security checks (like an input array with a maxLength)
404 The server can not find the requested resource.
The ID format is valid and you can't find the resource in the data source.
If you don't follow any standard architecture, you should define how you want to manage these cases and share your thought with the team and customers.
In many legacy applications, an HTTP status 200 with errors field is very common since very-old clients were not so good to manage errors.

Is it expected behavior that path is reset between requests in a single Scenario?

I'm trying to create a vanilla delete test, and our endpoints check Etags. The proper way to go about this IMHO is:
GET the object & read its etag header
Assign that header to the etag header in a follow up DELETE request
So I have something like this:
Feature: Delete with etag
Background:
* url config.url
* path 'path/to/entity/type'
Scenario: Retrieve Login page url
Given path entityId
When method get
* def etag = responseHeaders['Etag']
Given path entityId
And header Etag = etag
When method delete
Then status = 204
This seems like it should work, but what I'm seeing is that between the two requests the root path set in the Background is reset. Is this expected? It makes sense if the assumption is that if you are making multiple requests within a scenario, the subsequent requests could be to a different url, and resetting the path is necessary to avoid polluting it for the secondary host (since path is append-only).
As a follow-on, this is a pretty common scenario in my experience. Is there a better usage pattern to handle this kind of thing?
Simple, you just shape the "base URL" to match your REST "resource". url will not be re-set. path is.
* url config.url + '/path/to/entity/type'
And now this will work as you expect:
Given path entityId
The Hello World example shows this pattern if you look closely.

Always getting 0 rules when querying products/(id)/rules/count and 204 status from /rules

I'm contacting the API of my client's store on BigCommerce. I've verified the option set has a bunch of rules associated with it (8 product rules).
When I contact the api with
/api/v2/products/181/rules I get a 204 response.
This seems to be an incorrect response.
I tried then contacting
/api/v2/products/181/rules/count
and I get a response of:
{ count:0 }
How do I get a proper representation of these rules, as the API specification describes?
Thanks for any help you can provide. I'm stuck.
The response indicates that there are no rules associated with the product ID in your request. Are you sure that the option set you're referring to has been assigned to the product ID referenced in your request? It is possible that the option set has rules but the product does not have an option set assigned to it.

RESTful API - Ignore invalid PUT request?

I build a simple API for a bookmark manager, where the URL of record should only be stored once. Record 001 with www.example.com already exists beside record 002 with www.stuff.com.
If I update record 002 with the url www.example.com, should I ignore the complete request and send back an error message or is it better to update all valid parts and just send an errror message, that says, that the url/bookmark already exists?
With a PUT, the expectation is that the entire operation will succeed or fail:
The PUT method requests that the state of the target resource be
created or replaced with the state defined by the representation
enclosed in the request message payload. A successful PUT of a given
representation would suggest that a subsequent GET on that same
target resource will result in an equivalent representation being
sent in a 200 (OK) response.
https://www.rfc-editor.org/rfc/rfc7231#section-4.3.4
You should send an error for an invalid PUT (since the URL already exists and cannot be in two records at the same time) and not apply any of the other updates.
For partial updates you might consider a PATCH, but in this case I don't think you would go this direction since:
If the entire patch document
cannot be successfully applied, then the server MUST NOT apply any of
the changes.
https://www.rfc-editor.org/rfc/rfc5789