Just curious to know in which scenario we should go for #RequestParam and #PathVariable. I know that:
#RequestParam takes parameter value whereas #PathVariable takes placeholder value
#RequestParam can be optional (required=false) while making request whereas #PathVariable value has to be provided.
When we want to use #RequestParam we have to know the property syntax but for #PathVariable not required
Is there any other reason to go for specific one?
Use #PathVariable if you want to adhere to 'statefull' URLs.
For Example:-
/customer/:id Customer view/edit page
/customer/ Customer Add page
/customer/list List Customer Page
/customer/:cid/order All order of a Customer
/customer/:cid/order/:oid Specific order of a partucular Customer.
Wisely using Path Variable will result in URL that gives you hint/clue about what the resulting view/page means.
This also lets you support refresh,back & forward operation with no
extra effort.
#RequestParams can be used to exatract data which is not passed as path params. Your MVC handler can have combination of two as required.
org.springframework.web.bind.annotation.RequestParam is used to bind Query String.
org.springframework.web.bind.annotation.PathVariable is used to bind URL path.
org.springframework.web.bind.annotation.RequestBody is used to bind HTTP Body.
org.springframework.http.RequestEntity will give you some added flexibility in defining arbitrary HTTP Entity headers along with HTTP Body.
Best Practice:
If you want to identify a resource, you should use Path Variable.
But if you want to sort or filter items, then you should use query parameter.
Example:
/users # Fetch a list of users
/users?occupation=programmer # Fetch a list of user with filter programmer
/users/123 # Fetch a user who has id 123
you can get side effects. You don’t have to define other URL and other query parameter to achieve basic CRUD functions.You change HTTP method depends on what you want to do.
/users [GET] # Fetch a list of users
/users [POST] # Create new user
/users/123 [PUT] # Update user
/users/123 [DELETE] # remove user
Putting optional parameters in the Template URL will end up getting really messy, So I would recommend to put optional parameter in Query String.
Related
I have a single ID REST API that I need to extend to support multiple (up to 10Ks) IDs. Basically to run update on all relevant IDs instead of sending 10Ks request in network.
Current endpoint:
#POST
#Path("{id}/update")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ResponseVO updateBlockReason(#PathParam("id") int id, List<RequestVo> requestVo) {
One option suggested is comma-delimited values as stackexchange's answers-by-ids
Usage of /answers/{ids} GET
{ids} can contain up to 100 semicolon delimited ids. To find ids programmatically look for answer_id on answer objects.
This is the case on similar answers
http://our.api.com/Product/<id1>,<id2> :as James suggested can be an option since what comes after the Product tag is a parameter
But it seems awkward to me and RequestVo will be same for all IDs (which is currently is fine, but later to add such support will be harder)
It seems I need to change from Path variable to add it inside RequestVO
Which means the Id will be a JSON key, e.g.
[{
"id" : "1",
"name": "myAttribute"
"toggle": true
},
{
"id" : "2",
"name": "mySecondAttribute"
"toggle": false
}
]
Is this the correct approach or am I missing something?
Thank you in advance for any comments\answers
Current request VO
#Data
#AllArgsConstructor
#NoArgsConstructor
public class RequestVO {
private String name;
private boolean toggle;
// will add now private int id
}
My concern is also if I want (one of the requirement) to update with same request (as name=doA, toggle=true) for 10Ks Ids I'll have to duplicate request VO instead of sending ID separately
The best way is to keep id in your RequestVO DTO itself and not in URL as you have already suggested because even 100 ids in URL can make your URL very big and you are talking about 10K ids.
And again in future, the bit length of a single id may increase or later on you might need to update 50k or even 100K objects.
According to maximum length of a URL, there is no general specification on URL length but extremely long URLs are usually a mistake and URLs over 2,000 characters will not work in the most popular web browsers.
So I think your second approach is best here and will be good for future purposes also.
You may also want to use a PUT request because it makes more sense for an update request. So your code will become like this:
#PUT
#Path("/update")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ResponseVO updateBlockReason(List<RequestVo> requestVo) {
I find the path product/{id}/update questionable, because you could achieve similar behavior by mapping #Put-request to product/{id} itself. The READ, WRITE differentiation is already explicit by the Request-mapping.
Also, whether or not using verbs in restful urls is a topic for itself.
Assuming you could use plural endpoints, this could look like /products/{id}.
Because you want to batch/bulk update products, you could map #Put-requests to /products now, with a list of updated Products in the RequestBody. Keep in mind, that this somewhat complicates the Response, as you may have to return Http-207 for answering the correct status of the update for each element in the list.
I want 1 logical endpoint for update
You can have a logical service method for this, but not endpoints really.
You already mentioned the problem of /{id} in your path for bulk updates.
If you really, really need to, I would remove the #Put-mapping from /products/{id} and redirect to /products where the update content would be a single element list, or a little more sophisticated, distinguished by a mediaType (what again means two endpints, but a single url).
Edit:
I just happen to understand the VO-issue. You are not updating Products, but parts of it (the name RequestVO was misleading me).
This smells like a #Patch-mapping to me, where parts of a Product get updated.
So I still would use /products but with a #Patch-mapping.
When a client needs to replace an existing Resource entirely, they can use PUT. When they’re doing a partial update, they can use HTTP PATCH.
This brings up another issue, use #Post only if the id is unknown (usually before something is CREATED and gets an id assigned, for UPDATES use #Put and reuse the assigned id)
Using post is technically doable, but because of idempotece not advisable.
Why not just pass the list of your IDs in the body of your request as JSON array? the code would be:
#POST
#Path("/update/ids")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public ResponseVO updateBlockReason(#RequestBody List<Integer> ids, List<RequestVo> requestVo) {
...
}
I am trying to delete resource using id and name, so I have two different methods to delete the resource using id and name. The think I realized later is that this will throw me ambiguous http operation.
example Delete an animal from the database using following operation:
/animal/1 or animal/elephant
I do not believe query parameters is the right answer for this. You are trying to delete a particular resource and I feel path param would be the right answer for it (delete a resource with a sepcific path, query params are mostly used for Getting a resource). However, I am not sure how can I achieve this without getting an exception. Any ideas?
A resource should be identifiable by only one URL, in your case the ID.
Locating the object by other means is a search, aka a query, e.g. by name, even if names are guaranteed to be unique.
So, the following would be good, clear URLs:
/animal/1
/animal?name=elephant
/animal?color=grey
You could also using matrix parameters, e.g. if the tail of an elephant is a resource:
/animal/1/tail
/animal;name=elephant/tail
See URL matrix parameters vs. request parameters.
i need to expose Rest API which retrieve information about Brand based on brandId,
so i need to send brandId parameter.
from Rest Architecture and Design perspective, should i use Post (with the parameter in the body), or use Get and send the parameter as query string or header
You should use GET. POST is used to put or update some new information into service/database.
Try to read this: What is the difference between POST and GET?
And this: When should I use GET or POST method? What's the difference between them?
i used GET, and sent the parameter brandId as path variable
I've a problem with a GET operation in a REST WS. We have a Front-end panel with several filters for searching customers. The panel contains these filters:
Customer ID (Customer property)
Customer Name (Customer property)
Account number (Account property)
License plate (Vehicle property)
...
In the domain model we have 3 entities:
Customer
Account (A customer could have 1 or more accounts)
Vehicle (An account could have 1 or more vehicles)
How can I implement REST GET operation for this seach?
GET ..../customers/?name={name}&accountNum={accountNumber}&licensePlate={licensePlate} ?????
I think it is wrong because accountNumber and licensePlate don´t belong to customer resource. I don´t need these properties in the result expected.
I think about create new resource like customerFilter but It is no sense if I have to return a customer resource.
Any idea?
Thank you!
It will not pretend to be a specific answer for your question. But I think it will clarify something related to GET method.
According with URI Specification - RFC 3986 and Http Specification - RFC 7230, there are 3 kinds of ways to send data from client to server: via query, via path or via message-body.
When you are using GET method, it is not recommended to use message-body, because GET method can be cached for improving performance stuffs and these caches could ignore the message-body or reject the request:
A payload within a GET request message has no defined semantics;
sending a payload body on a GET request might cause some existing
implementations to reject the request.
So, you can choose now query or path. Both are in URL in this format:
http://example.com/{path1}/{path2}?query1=value1&query2=value2
What are the differences between these? according with RFC 3986 - Path and RFC 3986 - Query:
The path component contains data, usually organized in hierarchical
form, that, along with data in the non-hierarchical query component
(Section 3.4), serves to identify a resource within the scope of the
URI's scheme and naming authority (if any).
The query component contains non-hierarchical data that, along with
data in the path component (Section 3.3), serves to identify a
resource within the scope of the URI's scheme and naming authority
(if any).
As conclusion, you can design whatever you want. You can use for example:
GET .../customers?name={name}&accountNum={accountNumber}&licensePlate={licensePlate}
GET .../customers/{customerId}/
GET .../customers?customerId=12345
I don't see any issue with the url you have but your concern is also valid.
There is something that we need to take into consideration in this scenario. With this search what you expect to get as the response of the API call?
If you want response should contain information about customer only, when the search condition gets satisfied then /customer is right.
If you want some generic response consisting of Customer, Account and Vehicle info, you can have some generic terminology instead of customer in the url.
I hope this will help you.
Thanks :)
I am looking for a way to have complex URL mappings that would depend on the content of the database. For instance I show two URL mappings:
/{category}/
/{category}/{slug}/{id}
Categories can be for instance:
apples, pears, lemons -> resolve to FruitListController,
beans, onions, potatoes -> resolve to VegetableListController.
Note that those categories are stored in database and might be changed.
If I have in addition the slug and id, both of them must be checked against the database if they exist.
Can I somehow write some kind "Category handler", which would return the corresponding Category and associated Controller?
Obviously this is a problem of translating URL -> Request. Also, is there a way to generate backwards Request -> URL in similar way? I would like something like in templates:
<c:foreach="apples as apple"
${apple.name}
</c:foreach>
Use WebArgumentResolvers. They have access to the WebRequest to see your URL. The resolvers can do your database lookups. The FruitWebArgumentResolver could return a Fruit or return UNRESOLVED. The VegetableArgumentResolver could return a Vegetable or return UNRESOLVED. After the argument is resolved, the handler adapter can map to the RequestMapping that takes the specific type as an argument. For example,
#RequestMapping("/{catagory}/{slug}")
public void fruitSlugList(Fruit fruit, #PathVariable("slug") String slug){
To see an example of this, I have a blog post here that uses the same type of mechanism:
http://www.adamweigold.com/2012/01/using-multpartrequestresolvers-with.html