REST, multiple paramters in the URL will reach URL char limit at some point - rest

I have the following two API-methods:
1)
#GetMapping("search/findByProjectIds")
public ResponseEntity<List<DailyEntry>> getDailyEntriesFromProjectIds(#RequestParam long[] id) {
return dailyEntryService.getDailyEntriesFromProjectIds(id);;
}
An API-request looks like:
http://localhost:8080/api/dailyEntries/search/findByProjectIds?id=1001&id=1002&id=1003&id=1004
2)
#PatchMapping("/{id}")
public ResponseEntity<?> partialProjectUpdate(#PathVariable List<Long> id, #RequestBody EntryStatus status) throws DailyEntryNotFoundException {
return dailyEntryService.partialDailyEntryUpdate(id, status);
}
An API-request looks like:
http://localhost:8080/api/dailyEntries/1758,1759,1760,1761
That was the recommended way i found of sending multiple IDs for a GET/PATCH request.
Problem: In some cases i have a lot of IDs i want to send. With more data in the future, i might reach the URL character limit at one point. To avoid that, i could be sending the IDs in the Body instead of the URL. The problem is that a) GET doesnt have a body, i would need to use POST for it b) that would break our and the recommended REST-API design.
Is there a better solution?

Is there a better solution?
Not today, no.
GET gives you a couple important elements. One is that it is safe (by definition), another is that general purpose components all share the same understanding of the caching rules.
The only method in the HTTP registry that is close to that is SEARCH, but SEARCH is badly entangled with WebDAV, and isn't generally useful.
A possibility, which may or may not fit your needs, is to think in terms of a URI shortener; you find a resource by POSTING information, and you get redirected to a resource with a simpler identifier that means the same thing. (In effect, the server has a key value store: the key is the identifier, the value is all the junk that you had to put into the POST body).
It's analogous to creating a resource, and then using the identifier for the created resource from that point on. Which restores you to a situation with safe semantics and standard caching, but it isn't as straightforward as the case where all of the interesting things can just be encoded into the URI itself.

GET has querystring length limitation (Refer What is the maximum possible length of a query string?). If you anticipate more id, then better switch it to POST

Related

REST API allow update of resource depending on state of resource

I have recently read the guide on implementing RESTful API's in Spring Boot from the official Spring.io tutorials website (link to tutorial: https://spring.io/guides/tutorials/rest/)
However, something in the guide seemed to contradict my understanding of how REST API's should be built. I am now wondering if my understanding is wrong or if the guide is not of as high a quality as I expected it to be.
My problem is with this implementation of a PUT method to update the status of an order:
#PutMapping("/orders/{id}/complete")
ResponseEntity<?> complete(#PathVariable Long id) {
Order order = orderRepository.findById(id) //
.orElseThrow(() -> new OrderNotFoundException(id));
if (order.getStatus() == Status.IN_PROGRESS) {
order.setStatus(Status.COMPLETED);
return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
}
return ResponseEntity //
.status(HttpStatus.METHOD_NOT_ALLOWED) //
.header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE) //
.body(Problem.create() //
.withTitle("Method not allowed") //
.withDetail("You can't complete an order that is in the " + order.getStatus() + " status"));
}
From what I read at https://restfulapi.net/rest-put-vs-post/ a PUT method should be idempotent; meaning that you should be able to call it multiple times in a row without it causing problems. However, in this implementation only the first PUT request would have an effect and all further PUT requests to the same resource would result in an error message.
Is this okay according to RESTful API's? If not, what would be a better method to use? I don't think POST would be any better.
Also, in the same guide, they use the DELETE method in a similar way to change the status of an order to cancelled:
#DeleteMapping("/orders/{id}/cancel")
ResponseEntity<?> cancel(#PathVariable Long id) {
Order order = orderRepository.findById(id) //
.orElseThrow(() -> new OrderNotFoundException(id));
if (order.getStatus() == Status.IN_PROGRESS) {
order.setStatus(Status.CANCELLED);
return ResponseEntity.ok(assembler.toModel(orderRepository.save(order)));
}
return ResponseEntity //
.status(HttpStatus.METHOD_NOT_ALLOWED) //
.header(HttpHeaders.CONTENT_TYPE, MediaTypes.HTTP_PROBLEM_DETAILS_JSON_VALUE) //
.body(Problem.create() //
.withTitle("Method not allowed") //
.withDetail("You can't cancel an order that is in the " + order.getStatus() + " status"));
}
This looks very wrong to me. We are not deleting anything here, it is basically the same as the previous PUT method just with a different state we want to move to. Am I correct to assume that this part of the tutorial is bogus?
TL;DR: what HTTP method is right to use when you want to advance the status of a resource to the next stage without giving an option of going back to an earlier stage? Basically an update/patch that will invalidate its own pre-conditions.
something in the guide seemed to contradict my understanding of how REST API's should be built. I am now wondering if my understanding is wrong or if the guide is not of as high a quality as I expected it to be.
I wouldn't consider this guide to be a reliable authority - the described resource model has some very questionable choices.
From what I read at https://restfulapi.net/rest-put-vs-post/ a PUT method should be idempotent; meaning that you should be able to call it multiple times in a row without it causing problems. However, in this implementation only the first PUT request would have an effect and all further PUT requests to the same resource would result in an error message.
The authoritative definition of idempotent semantics in HTTP is currently RFC 7231.
A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request.
Note: "effect", not "response".
PUT /orders/12345/complete
means "please replace the current representation of /orders/12345/complete with the representation in the payload". In other words "save this file on top of your current copy". Saving the same file two or three times in row produces the same effect as saving the file once, so that's "idempotent".
HTTP does not define exactly how a PUT method affects the state of an origin server beyond what can be expressed by the intent of the user agent request and the semantics of the origin server response. It does not define what a resource might be, in any sense of that word, beyond the interface provided via HTTP. It does not define how resource state is "stored", nor how such storage might change as a result of a change in resource state, nor how the origin server translates resource state into representations. Generally speaking, all implementation details behind the resource interface are intentionally hidden by the server. -- RFC 7231
So in their CURL example
PUT /orders/4/complete HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*
The meaning of this message is "replace the current representation of /orders/4/complete with an empty representation". But the origin server gets to choose how to do that, and which standardized responses to return to the client.
So this is fine.
All work is transacted by politely placing documents in in-trays, and then some side effect of placing that document in an in-tray causes some business activity to occur -- Jim Webber, 2011.
In this case, the document we are putting into the "in-tray" happens to be blank.
#DeleteMapping("/orders/{id}/cancel")
I would never approve that choice in a code review. DELETE (like PUT) has semantics in the "transfer of documents over a network domain".
The DELETE method requests that the origin server remove the association between the target resource and its current functionality. In effect, this method is similar to the rm command in UNIX: it expresses a deletion operation on the URI mapping of the origin server rather than an expectation that the previously associated information be deleted.
Trying to hijack the method because the spelling is kind of like the domain action is the wrong heuristic to use in choosing methods.
Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.
The point being that we have a general purpose document manipulation interface, and we are using that interface as a facade that allows us to drive business activity. So we should be using our standardized message semantics the same way every other page on the web does.
#PutMapping would be defensible, using the same justification as we did for /complete.
what HTTP method is right to use when you want to advance the status of a resource to the next stage without giving an option of going back to an earlier stage? Basically an update/patch that will invalidate its own pre-conditions.
PUT, PATCH, and POST are all appropriate methods to use when editing the representation of a resource. Use PUT or PATCH when you are sending a replacement representation for the resource, use POST when you are asking the server to calculate what the edit to the representation should be.

REST endpoint: how to proper design an action on a resource?

I have the resource /contracts with the following structure:
{
name: "Contract name",
signedAt: 123213231,
// etc.
}
While basic CRUD operations are well clear (GET /contracts, GET /contracts/{id}, POST /contracts, etc.) some doubts come when I have to do some concrete actions on the resource.
One of these actions is the following:
sign: means the contract is signed, so the signedAt date will need to be updated with the moment (date-time) the contract was signed.
So far I've been thinking about these different approaches:
PATCH-ing the resource
This approach will mean having the following endpoint method:
PATCH /contracts/{id}
and just posting the signedAt date { signedAt: 123213231 } meaning that after this the contract will be signed.
What I don't like about this approach is that the signature date comes from the client, I was thinking that having this date initialized on the backend side whenever a contract is signed could be better and more consistent.
Totally discarded, as the signedAt date should be set on the server
side exactly at the moment the sign is done.
POST-ing a new resource
This approach will mean having the signature action as a resource:
POST /contracts/{id}/sign
with an empty body in this case as we don't need to pass anything else so, once it is posted, the backend side would be the responsible for having the signature date initialized.
POST-ing the resource using 'action'
Similar to the previous approach, in this case I would use a query parameter called action on the contract resource:
POST /contracts/{idContract}?action=sign
also with an empty body where ?action=sign. Like in the previous approach, once posted the backend side would be the responsible for having the signature date initialized.
Questions
What would be the proper way to have this designed at a REST API level?
Is any of the approaches above close to a good design or not?
Would I need to modify any of the approaches?
Is there any better alternative?
I have designed a few rest APIs myself but I am not a restful evangelist so my answer might not be the best. I would suggest some of the following:
Create a custom converter for date values in your rest service that accepts date AND other specific fields. If you checkGoogle reporting APIs for example they allow you to use specific date range and also CURRENT_WEEK, CURRENT_MONTH etc. So you can add such specific value and use it. For example PATCH signedAt=CURRENT_DATE and the API handles that properly.
Add a boolean signed field to the resource. Do a POST or PATCH with signed=true. This way you will be able to eventually query only signed resources easily ;) Also it might be the case that people care only about if it is signed than when it was signed
I wouldn't use ?action=sign or /contracts/{id}/sign because these are not RESTFUL and even if you do use GET and POST you would use them in a way to create a workaround in order to implement actions in your design which shouldn't have actions
just posting the signedAt date { signedAt: 123213231 } meaning that after this the contract will be signed.
On HTTP Patch
The set of changes is represented in a format called a "patch document" identified by a media type.
Rather than rolling your own bespoke media type, you might want to consider whether one of the standard formats is suitable.
For example: JSON Patch.
Content-Type: application/json-patch+json
[ { "op": "replace", "path": "signedAt", "value": 123213231 }
JSON Merge Patch is another reasonable option
Content-Type: application/merge-patch+json
{ signedAt: 123213231 }
From what I can see, the primary difference is that JSON Patch provides a test operation which gives you finer grain control than simply relying upon validators
But you are absolutely right - PATCH gives the client code authority to specify the time value. If that's not appropriate for your use case, then PATCH is the wrong tool in the box.
POST /contracts/{id}/sign
POST /contracts/{idContract}?action=sign
As far as REST/HTTP are concerned, these two choices are equivalent -- you are updating the state of one resource by sending an unsafe request to a different resource. There are some mild differences in how these spellings act when resolving references, but as request-targets, it doesn't make a difference to the client.
An option that you seem to have overlooked:
POST /contracts/{id}
action=sign
This has the advantage that, when successful, you get cache invalidation for free.
In a hypermedia API, the flow might go something like this: the client would GET the resource; because the resource hasn't been signed yet, the representation could include a form, with a "sign" button on it. The action on the form would be /contracts/{id}. The consumer "signs" the contract by submitting the form -- the agent gathers up the information described by the form, encodes it into the request body, and then posts the request to the server. The server responds success, and the client's cache knows to invalidate the previously fetched copy of the resource.

REST Design: Adding/Deleting a related entity from a given entity using REST

Let's suppose I have an Group of users and I want to add/delete users from the group. What I am confused about is what will be the best practice to design the urls. Here are the options
OPTION # 1
POST /groups/{groupId}/users -- The request body will contain the userId
DELETE /groups/{groupId}/users/{userId} -- The userId will be in the path and the request body will be empty
OPTION # 2
DELETE /groups/{groupId}/users -- The request body will contain the userId
POST /groups/{groupId}/users/{userId} -- The userId will be in the path and the request body will be empty
I believe both the answers are correct and I am guessing there is no right or wrong answer here, just personal preference.But I would like to know what is used wide-spread. I have been using OPTION # 1 because I read in some book (the name escapes me) that the data you are POSTing shouldn't be a part of the url while using DELETE there is no such best-practice restraint.
All inputs appreciated !
The first option is the most common, but that means nothing, since misconceptions about REST are widespread. As a matter of fact, #1 isn't REST at all, it's RPC pure and simple.
Adding a member to the collection can be done either through a POST to the collection /groups/{groupId}/users, with the location of the created resource returned in the Location response header, or through a PUT request to the final location /groups/{groupId}/users/{userId}. The POST should return a 201 Created response, and the PUT either that or 200 OK, if the resource already existed and was replaced by the new one.
To delete, the correct way is to use DELETE /groups/{groupId}/users/{userId}. It's not a matter of personal preference. POST is a method you use for operations that aren't standardized by the HTTP protocol. Simple deletion is standardized through the DELETE method. Implementing it through the POST method simply means you'll have to document that functionality, instead of relying on the standard itself. You'd use POST only if you are doing something fancy during the deletion, something that already requires the functionality to be documented.
The option 1 seems to be the most common one. I don't have the feeling that the option 2 is valid at all!

Updating a value RESTfully with Post

I'm rather new to REST so forgive me if this is a stupid question.
So, I have a customer resource. A customer has many credits. So, I imagine a URL for getting customer credits would be
customer/21/credits
(where 21 is a customer ID)
Now, how do I add to the credits, if I don't have the full amount of credits? E.g. a customer has 10 credits and I want to add 5. As I understand, if I'm using post I would do something like:
customer/21/credits?amount=15 (is this even correct?)
However, what if I just want to add to the existing credits? That is I want to send 5 credits and say add them to whatever the customer currently has? Do I define a kind of phantom resource such as addedCredits?
customer/21/addedCredits?amount=5
then behind the scenes, I just do credits += 5?
You need to define how you're going to treat "credits" in your system; it matters whether or not you intend to define them as resources or as an attribute of your customer resource.
In the examples below, I'm going to use XML to represent the resources/entities. This may work for you, but you'll need to have some consistent way of representing your resources in requests and responses - this will help you avoid using query parameters (e.g. http://example.com?foo=bar) to define data that belongs in the request body.
A couple of ways of representing credits:
If a "credit" is an attribute of your "customer":
<customer id="21">
<balance>10</balance><!-- aka credit -->
</customer>
Then you might as well just GET the customer, update the credit/balance with your client, and then PUT the <customer> back to /customer/21.
If a "credit" is its own resource:
You can POST the following to /credit:
<credit>
<dateApplied>2009-10-15 15:00:00</dateApplied>
<customer href="/customer/21"/>
<amount>5</amount>
</credit>
Or you can POST the following to /customer/21/credits (assuming that URI is a list of all of the <credit>s applied to the customer):
<credit>
<dateApplied>2009-10-15 15:00:00</dateApplied>
<amount>5</amount>
</credit>
This would "append" a new <credit> to the existing list. And also eliminates the need to provide the <customer> in the entity, since it's already present in the URI.
I would use the same URL.
POST to customer/21/credits with a POST variable called extraCredit set to 5. POST is supposed to be used for annotation of existing resources (or creating subordinate resources). There is no reason why you should need a new URL.
If an individual credit is a resource in your system that deserves its own URL, then the response URL from POSTing to customer/21/credits should include the URL of the new credit resource e.g. customer/21/credit/12.
You could define an XML representation of credits to POST to customer/21/credits, but I would not consider it worthwhile in this simple example. REST payloads do not have to be XML.
A URL like customer/21/addedCredits?amount=5 doesn't make sense to me because it doesn't really identify a resource. If someone issues a GET to customer/21/addedCredits?amount=5 what would you return to them?
The one thing you should definitely not do is change the state of the customer resource when someone GETs a URL like customer/21/addedCredits?amount=5. Since the title of your question acknowledges that you will need to use POST your probably realise this. GET is supposed to be safe, which means that issuing a GET shouldn't change a resource's state.
Ultimately the implementation is up to you. WHile URI query parameters are generally frowned upon, it doesn't mean you can't use them. Personally I would make the post URI something like:
customer/21/credits/add/5
but nothing says you can't do something like what you have or :
customer/21/credits/add?value=5
For starters using the URI query parameters should be a "bad smell" to you. Second you need to look at defining some mime types that your clients and server can talk in so for instance with your credit example:
If I do a GET on customer/21/credits I might get a document like this:
Content-type : application/vnd.creditstore+xml
<credits>
<user>21</user>
<credits>10</credits>
Add credits to this account
</credits>
This tells a client who understands your vocab that if they want to add credits to this user they need to post something to that link. This is HATEOAS (god I hate that acronym, I probably even spelled it wrong).
Now this is all completely off the top of my head, and I probably butchered that XML example but it should get you thinking in the right direction.

RESTful, efficient way to query List.contains(element)?

Given:
/images: list of all images
/images/{imageId}: specific image
/feed/{feedId}: potentially huge list of some images (not all of them)
How would you query if a particular feed contains a particular image without downloading the full list? Put another way, how would you check whether a resource state contains a component without downloading the entire state? The first thought that comes to mind is:
Alias /images/{imageId} to /feed/{feedId}/images/{imageId}
Clients would then issue HTTP GET against /feed/{feedId}/images/{id} to check for its existence. The downside I see with this approach is that it forces me to hard-code logic into the client for breaking down an image URI to its proprietary id, something that REST frowns upon. Ideally I should be using the opaque image URI. Another option is:
Issue HTTP GET against /feed/{feedId}?contains={imageURI} to check for existence
but that feels a lot closer to RPC than I'd like. Any ideas?
What's wrong with this?
HEAD /images/id
It's unclear what "feed" means, but assuming it contains resources, it'd be the same:
HEAD /feed/id
It's tricky to say without seeing some examples to provide context.
But you could just have clients call HEAD /feed/images/{imageURI} (assuming that you might need to encode the imageURI). The server would respond with the usual HEAD response, or with a 404 error if the resource doesn't exist. You'd need to code some logic on the server to understand the imageURI.
Then the client either uses the image meta info in the head, or gracefully handles the 404 error and does something else (depending on the application I guess)
There's nothing "un-RESTful" about:
/feed/{feedId}?contains={imageURI}[,{imageURI}]
It returns the subset as specified. The resource, /feed/{feedid}, is a list resource containing a list of images. How is the resource returned with the contains query any different?
The URI is unique, and returns the appropriate state from the application. Can't say anything about the caching semantics of the request, but they're identical to whatever the caching semantics are of the original /feed/{feedid}, it simply a subset.
Finally, there's nothing that says that there even exists a /feed/{feedid}/image/{imageURL}. If you want to work with the sub-resources at that level, then fine, but you're not required to. The list coming back will likely just be a list of direct image URLS, so where's the link describing the /feed/{feedid}/image/{imageURL} relationship? You were going to embed that in the payload, correct?
How about setting up a ImageQuery resource:
# Create a new query from form data where you could constrain results for a given feed.
# May or may not redirect to /image_queries/query_id.
POST /image_queries/
# Optional - view query results containing URIs to query resources.
GET /image_queries/query_id
This video demonstrates the idea using Rails.