REST URL concept for subObjects - java

I want to build my application RESTFul.
Whats the normal URI concept for subObjects.
My Example:
I have a some users. I get a user by /users/:id. Now this user can be rated. Is the best concept to do the userRatings (GET,POST,PUT,DELETE) over /users/:id/ratings or handle them as an own object over /ratings/. Or a mix of both?
My questions:
When it is /ratings/ how i get a list of ratings for a specific
user (/ratings/?userId=1?).
Is the object normally in the URI plural or not?

The URL scheme depends largely on what you need to do with your data model, e.g. how you want to query those ratings:
if you only ever want to display a single user's ratings, put them under /users/:id/ratings
if you want something like "10 top-rated users", consider something like GET /users?toprated -- here you're looking for users, so the URL should signify that by being /users
if you want to get ratings across several users, e.g. to find all ratings containing the word "outstanding", /ratings/ makes more sense: The search is then naturally expressed as GET /ratings?q=outstanding -- here you want ratings so the URL should be /ratings plus a request parameter to restrict what kind of ratings you want
In either case, unless you're building a huge, public API and expect lots of clients right on launch day, go with what works and change the URL scheme if you need to.
As for the singular/plural debate: Use plural for path segments, i.e. /users, /ratings because it follows naturally from REST's building blocks of a "resource" and "collections of resources": There's the collection of users at /users (accepting GET, POST) and there's a single user at /users/:id (accepting GET, PUT, DELETE).

Related

Should you expose a primary key in REST API URLs?

I'm very new to Spring. I'm trying to create a REST API using Spring Boot and I'm stuck whether to expose my user's primary key or not which also happens to be their email. Something like api/user/example#gmail.com. A big part of me says it's okay since it would sensible to expose it as it is the identifier for that specific record when viewing, deleting, and updating. Is there a security risk for this? What is the best practice for such implementation? Right now I'm combining the #PathVariable and #RequestBody. I didn't like the idea of putting my primary key in the RequestBody thinking that it might pose a risk...or is there?
#RequestMapping(value = "/updateUser/{customerEmail}", method = RequestMethod.POST)
public ApiResult updateCustomer(#RequestBody UserDetailsDto userDetailsDto, #PathVariable String customerEmail) {
//service call...
}
First of all, user e-mail is often considered to be PII (Personally Identifiable Information). As such it would be unwise to put it into a URL, because you should not put any sensitive information into the URL. Header - ok, body - too. But not into the URL. The reason is, that all the proxies/load balancers/other infrastructure you have or might have in the future will always be allowed to log URLs for debug reasons. And you don't want your sensitive data to leak across the components like this. No company policy would ever allow that.
Spring is a good framework of choice, usually as long as the identifier is unique it should be fine, the problem with using an email is you are exposing your users data more easily which could be problematic to the users, I would suggest you rather use a string of unique characters as an identifier in the form of:
http://api.example.com/user-management/users/{id} as an example http://api.example.com/user-management/users/22
in this case identifier of user 22 has the email example#gmail.com in this way you are not exposing sensitive data when doing an update here is a link that gives guidance on best naming practice https://restfulapi.net/resource-naming/.
Another tip given in the link provided is to avoid using URI's as CRUD (Create, Read, Update, Delete) functionality "URIs should be used to uniquely identify resources and not any action upon them".
Any sensitive information (in this case email but in other case that could also be your database autoincremented primary key field ID in your table) should not be exposed.
Once way to go around that that I know and I use is to have 2 fields. For example, I have table USER {ID, USERID, NAME, ...}
Above, ID is autoincremented Long field representing PK.
USERID on the other hand, is a field generated of random characters or GUID which I use to pass back and fort in REST calls.
So, I might have record in USER table as:
USER {1, "a23asf60asdaare998700asdfasr70po097", "Mike", ...}
If I were to pass ID=1 back and forth, a malicious user could easily deduce what it is and how to query next user. For that reason, i pass USERID which represent a public and safe version of ID that can be passed and no one can know what would be the USERID of next user.
So, your response model, dto model etc should have these fields and response model should return USERID instead of returning ID. And you can use JPA to find the user by the USERID (so, based on that, that method must be called in this case findByUserId).
The same would apply for your case where you use email instead of ID if you want dont want to expose user emails which make sense to me.
Hope that helps.
I think it's more a matter of taste and personal beliefs rather than objective aspects.
Since HTTPS is more or less mandatory today, it's a lot harder to obtain the e-mail address by just sniffing with a tool like Wireshark.
So what's the possible risk? Since users have to be authorized to call this endpoint, they know at least their own e-mail address and most likely used it to authenticate. So a user can't modify or acquire the data of another user, if properly implemented.
A problem which may be of concern is that it might be possible to check for a registered e-mail during the registration process. Depending on what kind of application you're developing, this might be an issue. To give a brief example of such a case: Imagine a catholic priest registered on a porn site or the e-mail address of your husband/wife registered on a dating platform.
So may advice: Force HTTPS and you are pretty fine to use them as a primary key. However, if you have the possibility to abstract this, I'd do so. A numerical key or username may be a better choice and also easier to handle - but it makes no difference. Imagine if you have an endpoint to acquire the user's data, including e-mail address. It just doesn't matter if you acquire this data by a numerical key or by the e-mail address. In the end, you end up with the e-mail address in the response's body. And if this body is accessible by someone, he can also access the username and password, thus rendering any security measurement you've taken useless.

Best URL structure for relation many-to-one

I'm using Spring Boot (generated by JHipster).
I have the following services:
/api/market/
/api/market/:id
and
/api/product/
/api/product/:id
all those with GET, PUT, POST and DELETE. But I need to implement one more specific service.
This services should return all the products inside the market X. But to do that, I was thinking to pass in the URL path this call: /api/product?marketID=1, but I will have to make a select in the market table and then get the products (will be easier search in only one table by market_id field).
I don't know if this URL is the best structure and also this kind of search. I know you can search of a specific field on the table the you do a filter, but I tested and I was not able to get a relation field.
I'd like to make a recommendation for how to structure your API, then provide a possible answer to your question.
Typically, RESTful APIs follow the plural-singular principle: given all markets (plural part), find market with id 5231422 (singular part). Reflect that in your URLs with /api/{plural-noun}/{singular-identifier}. So your API would end up looking more like this:
/api/products (all products in the system)
/api/products/:productId (a single product in the system)
/api/markets (all markets in the system)
/api/markets/:marketId (a single market in the system)
To answer your question, then: I recommend you use the "Russian stacking doll" URL design. It appears that your design suggests that a single Market can contain several products in it. Thus you might find this kind of URL a bit clearer: /api/markets/:marketId/products, which fetches all products within that market.
Generally, you want your URL's to be semantic and navigable. So based on what you've already got:
/api/market/:marketId/product
In addition, it is usually recommended to go with pluralization so I would do the following:
/api/markets/:marketId/products

Deletion of multiple resources in JAX-RS Service jersey implementation

I am new to restful services and willing to get some ideas from the experts.
The application which will be accessing my service is having a datatable-grid (each row of the grid represents an Employee Object/Entity) where user can delete more than 1 records at a time(based on the number of checkbox selected by the user). In such kind of a delete operating how will be the URL representation and how will the data be send to the service?
My Idea
Since the number of rows deleted by the differs (based on the number of checkbox selected by the user), hence I am opting for the query string and below will be the URL representation using which I can get the data in my service:
/deleteEmployees?id=1,2,3
i.e. a comma seperated values of the id's which will uniquely identify a record in the table.
Based on my Idea, I have a few questions:
1) The query String mentioned above contains of comma-seperated values (i.e. Ids). Is it a valid URL where query strings will contain this kind of values?
2) Is there any restrictions in defining the query strings of an URL (like the way I did using csv)?
3) Any other alternative of achieving the same in a better and efficient manner?
P.S. I am new on this and hence looking for different ideas from the experts and try to understand what is correct and what is not.
A comma separated list of Employee ids is a fine way to do it, but I wouldn't put it in a URL with an action in it, ie. /deleteEmployees?id=1,2,3. REST is more about identifying resources, rather than actions, in URLs. I would either loop through each one of the employee ids to delete and send an HTTP DELETE request for each
DELETE /employees/1 HTTP/1.1
DELETE /employees/2 HTTP/1.1
DELETE /employees/3 HTTP/1.1
Another alternative is to send one HTTP DELETE request to a URL like /employees, keeping the suggested REST identification of resources and using HTTP methods. You would pass the list of ids in an HTTP header.
DELETE /employees HTTP/1.1
Employees-To-Delete: 1,2,3
Take a look at this answer for character restrictions in URLs.

Restful Architecture for Searching for Resources in MySQL database via LIKE

Basically I have a /orders resource and I want users to be able to do a search for orders based on different criteria.
Let say order has three columns: orderNum, orderDate, and customerName
Now, if a user wants to find all orders with order numbers like 'manual', I would do a query like
SELECT * FROM orders WHERE orderNum LIKE '%manual%';
and do not worry I used parametrized statements. I was thinking I could add a form parameter if I am accepting x-www-form-urlencoded in the body indicating whether the user wants to search by orderNum, orderDAte, or customerName, but this is starting to feel like REST-RPC. I would prefer to do it in a more RESTful manner. Any ideas?
Found this question that was relevant. It is basically the same question. I will rely on SQL errors if a request is made to search for objects based on non-existent properties, and then inform the client, providing a list of possible searchable properties.
RESTful URL design for search

Creating friendly urls to dynamic resources in struts2

I have a struts2 application with a single page that may show one of a number of values stored in a database. The application is for a school with many departments and each department has many programs. The department page is accessed using a url like this
department.action?id=2
and the DepartmentAction will load the Department with id = 2 for display. All this is fine if the user is just browsing around the site but it gets uncomfortable if I want to provide a link to say the Engineering department in the newspapers. The link will have to be www.myschooldomain.com/department.action?id=2. I see a number of problems with this.
First, it is not user friendly. Second, it is prone to be broken because the departments are dynamically maintained and the id for a department could change without warning making the link unstable.
I would prefer to print a url like this: www.myschooldomain.com/department/engineering and have that somehow go to department.action?id=2.
My thoughts so far: create an action that will parse the url for the department name at the end then look it up by name. Maybe I could add a friendlyurl field to the database for each department.
But the question is: Is there a better way to do this in struts2?
Thanks.
Update (May 2009): I just happened to stumble back over this question and thought that I would say what I did to solve it.
I created a new package in the struts.xml called departments. In this package there is only one action mapped to *. So it catches all requests to mydomain.com/departments/anything.html.
In the action class I simply parse the url and look for the part between departments/ and .html and that is the name of the department so I can do a lookup in the database for it. This has been working fine for almost 5 months now and I have implemented it for other areas of the site.
You could use the URL Rewrite filter
This avoids the need for any additional servlet or Java code but requires XML descriptors.
This is normally done by mapping a servlet to, in your case '/department', and then using the path information (e.g., '/engineering') within the servlet to determine the ID.
Since the Struts2 dispatcher doesn't implement this behavior, it might be simplest to write your own servlet. This servlet would be configured with a map of valid "friendly" names to the unfriendly numeric identifiers. This could be an actual Map or it could be done with a database finder method.
The result of getPathInfo() would be used to look up the ID, and the request would be forwarded to the department.action. Handle the null case too, which means the user is trying to browse the /departments/ directory.

Categories

Resources