REST conventions for URI - rest

At work, I've seen routes like this:
/people/:id/edit
But I reckon such routes are hard to build programmatically. To my mind, better, is:
/people/edit/:id
That way, you can do stuff like:
const peopleEditRoute = '/people/edit'
...
<Route path=`${peopleEditRoute}/:id`
...
<Link to=`${peopleEditRoute)/${id}`
However, a colleague commented that '/peoples/:id/edit' is more conventional - it follows REST
Are they right?

As per #jonrsharpe's comment, the route should be:
/people/:id
...for all of GET, POST, PATCH etc...

/peoples/:id/edit' is more conventional - it follows REST
Are they right?
No; REST doesn't care what spelling conventions you use for your resource identifiers.
I reckon such routes are hard to build programmatically.
They shouldn't be. URI Templates are a common solution, and I would expect library support in most languages where you are likely to be writing web code. (Hint: do you really want to be writing your own logic for deciding when to encode your data?)
One consideration for path segments is relative resolution: in particular the use of dot segments to move around an identifier hierarchy.
In other words, if you are in the context of the edit resource for some person, are you more likely to want a relative reference to another resource for the same person, or to the edit resource of a different person?
As noted by #jonrsharpe, if you are creating an API that is "of the web", then you typically will request the modification of a resource by sending a request (PATCH/POST/PUT) that identifies that resource as the request target.
The point here is cache invalidation. Caching is a constraint in the REST architectural style, and general purpose HTTP components know that responses can be re-used to service other requests, and know that successful unsafe requests invalidate previously cached responses.

Related

What is the best practice to design the rest api url if one resource identifier is a path

It is straightforward to put resource id into url if it is a int or long type. e.g.
GET files/123
But my problem is that my resource identifier is a path. e.g. /folder_1/folder_2/a.sh because the underlying implementation is a filesystem. So I can not put it as part of rest api url because it is conflict with url path.
Here's approaches what I can think of:
Put the path id as the request param. e.g.
GET files?path=/folder_1/folder_2/a.sh
Encode/decode the path to make it qualifier as part of url.
Introduce another int/long id for this resource in backend. And map it to the path. The int/long type resource id is stored in database. And I need to maintain the mapping for each CURD operation.
I am not sure whether approach 1 is restful, approach 2 needs extra encoding/decoding, and approach 3 needs extra work to maintain the mapping.
I wonder what is the best practice to design the rest api url for this kind of case.
Simple:
#GET
#Path("/files/{path:.+}")
#Produces({MediaType.TEXT_PLAIN})
public String files(
#PathParam("path") String path
) {
return path;
}
When you query files/test1/tes2 via url output is:
test1/tes2
Just put the path after a prefix, for example:
GET /files/folder_1/folder_2/a.sh
There isn't a conflict, since when the request path starts with your known prefix (/files/, in the above example), you know that the rest should be parsed as the path to the file, including any slashes.
Well, my experience designing "restful" APIs shows that you have to take into consideration future extensions of your API.
So, the guidelines work best when followed closely when it makes sense.
In your specific example, the path of the file is more of an attribute of the file, that can also serve as its unique ID.
From your API client's perspective, /files/123 would make perfect sense, but /files/dir1/file2.txt is debatable.
A query parameter here would probably help more, much like what you would do if you wanted to retrieve a filtered list of files, rather than the whole collection.
On the other hand, using a query parameter would also help for future extensions, since supporting /files/{path} would also mean conflicts when attempting to add sub-resources to your files endpoint.
For example, let's assume that you might need in the future another endpoint /files/attributes. But, having such an endpoint, would exclude any possibility for your clients to match a file named attributes.

REST url for nested resources

Which is a proper way of creating REST path ?
Say i have REST resource like,
base_url/api/projects/{projId}/sprints/{sprintId}/.....etc
I have more than 5 path params like this in a resource url. Is it proper to have so many path params or we have to cut it to different resources like,
base_url/api/projects/{projId}
base_url/api/sprints/{sprintId}
...etc
The condition here is , a sprint cannot exist without a project and so on. If we need to cut the resources to different paths, are there any standards on which conditions we can cut them?
REST doesn't care about the URI design. That's a misconception.
The readability of a URI is desirable but not mandatory in the REST architectural style.
As defined in the RFC 3986, the URI syntax is organized hierarchically, with components listed in order of decreasing significance from left to right separated by /. If a sprint cannot exist without a project, you can use the following to express such hierarchy:
/api/projects/{project-id}/sprints/{sprint-id}
However, if the URI gets too long and you have many parameters to pass around, there's not issues in splitting it:
/api/projects/{project-id}
/api/sprints/{sprint-id}

Naming a GET with alternative query options

Assume you have a REST service that already gets users by id, so the url looks something like
GET /users/{userId}
But you want to create a duplicate web service that gets users by email, so:
GET /users/{email}
Which is better?
Method 1:
Same method:
/users/{input}
...
if(isEmail(input)) queryByEmail(input);
else queryById(input);
Method 2:
Different Method:
GET /users/{userId}
GET /usersByEmail/{email}
Since there is no actual overlap between email addresses and IDs. I would just use same endpoint for both. Especially if GET /users/{id} is already a published interface.
So, I would go with 1st method.
GET /users/{identifier}
Then on the API server you have to add a small check, whether {identifier} is a number or not.
I would also like to note, that "pretty URLs" do not make it REST :) You probably will want to watch this lecture: https://www.youtube.com/watch?v=pspy1H6A3FM
My personal preference would be,
GET /users/id/{id}
GET /users/email/{email}
But it all depends on what you the rest endpoints to look like.
Which is better?
REST doesn't care; from the perspective of the client, the URI is opaque. The clients concerns are following links/submitting forms/completing templates.
Information encoded into the URI is done at the server's discretion and for its own exclusive use.
So you can use any spelling you like. As a rule, it's a good idea to conform to local spelling conventions (in much the same way that your variable names in code should conform to your coding conventions). But your clients shouldn't need to know the details of those conventions.
/users/{input}
...
if(isEmail(input)) queryByEmail(input);
else queryById(input);
Note that you aren't necessarily deeply committed to one approach; that's part of the point of decoupling the identifiers from the representations. For instance, your implementation could just as easily look like
/users/{input}
...
if(isEmail(input)) redirectTo(/users/email/{input});
else redirectTo(/users/id/{input});
which allows clients that have bookmarked the original URI to arrive at the correct resource.

Moving child resource to another parent in REST

I have a REST service.
And now I need to have functionality to move some child resources from one parent to another, for example move a book from one author to another.
My variant is:
POST /api/books/x/moveto/y
But how to create such architect the RESTful way?
From a REST point of view, URLs should be used to locate the resources rather than expressing operations. To express operations, the existing HTTP verbs should be used.
Looks like your "move" operation is all about replacing the author of the book.
And the PUT method seems to be the way to go:
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. [...]
So, you can have an endpoint like the following:
PUT /api/books/{bookId}/author
And the request payload will contain a representation of the new author.
I think in this case updating the author as suggested in Cassio's answer is a good solution. For less obvious "actions" I use PATCH endpoints. Consider archiving a book:
PATCH /api/books/{bookId}/archive
The intent is obvious -- archive the book with this identifier. For more complex actions, include a body or use a query string parameter. For instance, moving a book out of one category and into another (assume a book can have 0-many categories):
PATCH /api/books/{bookId}/move
{
fromCategoryId: 100,
toCategoryId: 200
}
Or:
PATCH /api/books/{bookId}/move?fromCategoryId=100&toCategoryId=200
In the end, IMO, what matters most is readability and consistency. There is not necessarily a "right" way to do this sort of thing.

REST - basic principles - Where to put the new and edit words

I'm wondering where to put the edit, and new keywords by rest application. I'll use express-resource in a project, and the default settings are these:
GET /forums -> index
GET /forums/new -> new
POST /forums -> create
GET /forums/:forum -> show
GET /forums/:forum/edit -> edit
PUT /forums/:forum -> update
DELETE /forums/:forum -> destroy
There is a problem with this solution: there is not a real resource behind the new and edit. I mean the URL-s refer to resources, and after any slash is a sub-resource.
For example:http://my.example.com/users/1 represents:
var firstUser = {
name: "John Smith",
birthDate: new Date(1952,10,4),
hobbies: ["skiing", "football"],
...
}
And http://my.example.com/users/1/birthDate represents:
firstUser.birthDate
But by http://my.example.com/users/1/edit there is no such property:
firstUser.edit
So something is wrong with this conception.
Where is the real place of these keywords? In queryString or in headers?
From the perspective of a REST API these do not exist anywhere as they are not related to the representation of resources. They are actions upon resources and therefore expressed by the HTTP methods used. They would not bee needed if you were to create an external client that uses the API.
There is likely a need to provide some support for this type of functionality so that something like a UI could be presented, but that is the concern of the particular application and not the API itself. At that point it becomes discretionary but I would certainly avoid using headers as that would be pretty outside of conventional practice. But by headers it appears that you actually meant URI path. Out of those 2 I would say the path is the better option since it clearly defines any type of UI as a distinct resource and would keep it apart from the clean API, while using a query string on a part of the API would more tightly (mistakenly) associate it with the underlying resource.
Some update after a year or so:
edit and new should be hyperlinks
these links are just the representations of possible operation calls
by following them it is possible to manipulate the resource they belong by sending representations of the intended resource state, and/or by calling the proper methods
these terms are no resources, they don't have their own URL (resource identifier)
Thanks the advices Matt Whipple!
I think the best way to learn REST is reading the Fielding dissertation. There are many tutorials out there, but the authors of most of these does not really understand REST.