How to create right API URLs for getting data - rest

I'm creating a simple API which works with geographical data.
Some URLs look very simple like:
GET /towns/{id}
or
GET /towns
Now I want to get a town by alias, should I use this kind of URL?
GET /towns/alias/{alias}
What if I also want to get a list of towns located near certain town?
GET /towns/closest/{id}/radius/{radius}
I understand that my URLs can be any I want. What is a canonical way to do it?

I understand that my URLs can be any I want. What is a canonical way to do it?
There isn't really a "canonical way" to design URLs, any more than there is a canonical way to name variables -- there are only local spelling conventions.
RFC 3986 distinguishes between hierarchical and non-hierarchical data:
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 effect of using hierarchical data is that you can take advantage of dot-segments to compute one URI from another.
For example
/town/alias/{alias}
/alias/{alias}
Both of these spellings are "fine", but /town/alias gives us the option of using dot segments to specify an identifier under /town
/town/alias/abc + ../123
=> /town/alias/../123
=> /town/123
That can be handy when it allows you to re-use a representation for multiple resources in your hierarchy.

Yes it can possible through the URL routing.You can send any number of parameter through url.
Can you please confirm the technology you used?

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.

What is the best way for my rest api uri name to include module name that the ressource belongs to?

I'm wondering what is the best way for my rest api uri name to include the module name that the ressource belongs to? lets clarify this, my rest api should expose the details of Object-A and should also expose the details of Object-B, in this case i can't use the ressource name ipAdresse:port/details because there is two details types.
add to this that i should not use the nesting style like this ipAdresse:port/objectA/:id/details.
So in this case, is it better to do it the following way (include the parent ressource or module name in the url):
ipAdresse:port/objecta/details
or this way (using hyphen):
ipAdresse:port/objectb-details
thanks
There's a small advantage to using path segments, if you have a family of these documents that want to link to each other
/objecta/details
/objecta/comments
/objecta/pricing
These resources can all reference each other using dot segments (ex: ../comments), which means that you don't have to specify the "objecta" part in the links. In other words, you could move the whole family of identifiers to a different location in your hierarchy, and relative resolution would just work.
/objectb-details
/objectb-comments
/objectb-pricing
Each of these paths is a single segment, so dot segments remove the entire path, which you would have to replace (ex: ../objectb-comment), and if you decide to replace the objectb prefix with something else, you also need to update all of the links.
In effect, using / gives you a little bit of future proofing.
That said, if the hyphen-minus is part of the name of the thing, then leave it in the identifier.
/objective-c/comments
If you bring one of these to me in a code review, I'm going to think you've lost the plot:
/objective/c/comments
/objective-c-comments
But of course they will work just as well (the machines don't care) as long as the identifiers match the syntax described by RFC 3986.

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.

What is a 2-dimensional key-value format that Api Blueprint can understand?

I'm developing api documentation for a RESTful search API using Api Blueprint. I would like to be able to pass filters to the API so I can assemble:
filter[filtername1]=filtervalue1
filter[filtername2]=filtervalue2
Per this question, I'm using percent encoded square brackets, but unlike this question, it's not possible for us to describe every possible key name:
How to format hash-based parameters in the URL when creating Blueprint API doc?
I want the key name to be variable, since it could be any field in the source data. Does this work?
## Key-Value-Test [/api/v1/keyvaluetest?term={term}&filter%5B{field_name}%5D={field_value}]
+ term
+ filter_field
+ filter_value
Is there a recommended format for a two-dimensional array like this? It doesn't seem like this would work in Dredd because + filter_field doesn't really match filter[filter_field]
I am afraid that API Blueprint and Apiary does not yet allow these kind of dynamic URL definitions.
API Blueprint and Apiary only allows URI Templates as defined in RFC 6570
The following URI Template is not valid according to that RFC
GET /resource?year={year}&month={month}
You can change the URL to define something like the following:
## Key-Value-Test [/api/v1/keyvaluetest{?term,field_name,field_value}]
+ Parameters
+ term: a
+ field_name: b
+ field_value: c
There are two caveats with this method:
You can only give one field name and field value for the parameters. If you want more field parameters, you have to extend the URL.
You have to change the API url which I don't think you would want to.
Please start a feature request at http://support.apiary.io if you have any.
API Blueprint uses URI Templates standard. There are ways to express and expand arrays (see section 3.2.1), however, it expects "standard URI approach", meaning the URI would be expanded as follows:
/api/v1/keyvaluetest?term=yourterm&filter=filtervalue1&filter=filtervalue2
which is a "standard" way of doing arrays, except the most popular web language popularised your way back in 2000s.
The templates are designed for expansion: give it a bunch of variables and a string, and you'll get a properly-formatted string. As far as I am aware, there is no "wild match" (inserting pattern-match variables at a certain position in string).
The only solution I can think of within the realm of URL templates would be taking advantage of explosion modifier (see composite values):
/api/v1/keyvaluetest{?keys*}
which, given associative array of values [(filter%5Bfiltername1%5D, filtervalue1), (filter%5Bfiltername2%5D, filtervalue2) ] should expand properly.
However, I am not sure how to specify those in MSON as I don't think there is a support for "dynamic keys" and I think most of the tooling wouldn't handle it (yet).
Might be worth asking.

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.