Naming a GET with alternative query options - rest

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.

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 conventions for URI

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.

What REST action should I use for Validate?

I have a design question on REST. I need to expose a validate method as a rest resource. Let us say it looks like this
public ValidatedResult validate(ObjectToBeValidated object)
ObjectToBeValidated is a class that contains the actual Object and also some parameters concerning the validation.
When I design this as a Restful resource, which action do I use? From my understanding GET is the action that best suits this case. If that is so, how I can pass my ObjectTobeValidated as an object but not as URL parameters? I shy away from URL parameters because ObjectToBeValidated may contain a lot of properties, ending up with an URL like below which is feel is too long
http://localhost/rest/validate?prop1=somevalu&prop2=somevalue&prop3=something&prop11=somevalu&prop22=somevalue&prop33=something
Any help would be appreciated
Thanks
Kay
The HTTP standard allows you to use the POST method. It does not necessary need to have a side effect.
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
HTTP 1.1 / method definitions / POST
In your case you can do something like this if you want to follow the noun-verb approach Tim suggested:
POST /api/my/object/validator
Be aware that by REST the messages must be self-descriptive, so either you need a vendor MIME type or you need to add meta-data e.g. RDF to describe what this link does and what params are allowed. Otherwise we are not talking about REST, just a regular webapp.

RESTful URL for adding record to a record

What's the correct "RESTful" URL for an action that adds a child record to a parent record?
For example, if I wanted to provide a URL for adding a "comment" record to an "order" record, how should I format it?
My first thought was something like:
PUT http://example.com/order/12345/comment/add
I work in Django, which uses a similar pattern, so this seemed most intuitive. However, reading over some RESTful design guides like this one suggests that this might be bad practice, as they argue the "PUT" and "add" are redundant and therefore might create confusion.
I would do the following:
POST http://example.com/order/12345/comment
The put action and the add part of the url are redundant. But there is no hard rule on any of this. I see apis having that form, even from major vendors, and sometimes simply remark "The put action and the uri segment are redundant" Sometimes I say nothing at all and just call the endpoint. If I were writing an api, I would probably leave off the add part.
there are few points to make your request RESTful:
1) Use resources names in the URL in plural and not in a singular form (orders instead of order)
2) never use ACTION names in your URL such as (ADD) in "comment/add"
3) since you are adding a "NEW" comment without knowing any IDs of hands you should use POST request.
Finally, the URL I would recommend is:
HttpVerbs = POST
http://api.example.com/orders/12345/comments
That should add a new comment to your order#12345
There is no one-size-fits-all answer to your question. Rest URLs can be whatever you want them to be. At the end of the day, they are routes that get mapped to a method. I wouldn't worry too much about the "best" URL. I prefer to find a standard that works for me and then move on to bigger, more important things. As long as clients know what the URL is, they will be fine.

REST - GET best practices for special characters

We have REST API's. I was trying to figure out the best way to do a Get with some special characters.
Currently, we have something like this: http://myhost.com/api/book/name=HarryPotter
The above URL works just fine, but gets complicated when certain special character's are included in the queryparam like '&' or '/', which will result in "No operation matching request path ... is found, HTTP Method : GET, ContentType : /, Accept : /,"
for ex: http://myhost.com/api/book/name=Dark/Thirty.
This will consider the '/' in 'Dark/Thirty' as an URL separator.
What is the best practice to be able to search such queries. Is using a JSON a better practice, if yes should I be using a GET or a POST? I believe it should be POST, as any slash in the query param is treated as an Url separator.
Meaning: even this would fail for GET. http://myhost.com/api/book/search={"name"="Dark/Thirty"}
And since this is actually not a POST i do not want to use it. As I am just listing out the books that meet my search criteria and not modifying or adding anything.
Any guideline in tackling similar problems?
This link is a good read. In essence, if your Dark/Thirty is an identifier (i.e. uniquely identifies a resource), then modify it (in a predictable pattern) so that it does not have the special characters; e.g., DarkThirty or dark-thirty. If it is, however, a search term, then you would be better served not to make it RESTful, but just pass it as a normal parameter; that's what they're for.
The difference between GET and POST is not what characters are in it, but what the objective is. GET is for getting stuff: it should be free of side effects. A search, or retrieval of a page should be a GET. POST effects changes to a server. It is improbable you would need to make an operation that both requires sending more data than URL allows, and at the same time makes no changes on the server but simply renders a new page (allowing for exceptions like Shazam or TinEye).
Dealing with special characters in GET parameters is the job of URL encoding; if you have http://myhost.com/api/search?q=Dark%FThirty for a search, your site is no less good. There are two primary drivers for REST, as I understand them: human-friendliness and SEO-friendliness. Search does not need to be either. REST exists to identify resources, in my understanding; and search results from a query are not a resource.
To summarise, I'd go with:
http://myhost.com/api/book/dark-thirty (the resource is the book)
http://myhost.com/api/search?q=Dark%FThirty (the resource is the search procedure, with arguments)
URL encoding sounds like the easiest thing to do in your case, particularly since you already have a URL structure set up for your application that looks like http://myhost.com/api/book/name={internal-identifier} where internal-identifier resolves to your book name (encoded, of course).
From the REST perspective, it doesn't particularly matter whether the URL represents a query that can return a collection of resource representations or uniquely identifies a specific resource. You can use this structure for both.