How to use URI as a REST resource? - rest

I am building a RESTful API for retrieving and storing comments in threads.
A comment thread is identified by an arbitrary URI -- usually this is the URL of the web page where the comment thread is related to. This design is very similar to what Disqus uses with their system.
This way, on every web page, querying the related comment thread doesn't require storing any additional data at the client -- all that is needed is the canonical URL to the page in question.
My current implementation attempts to make an URI work as a resource by encoding the URI as a string as follows:
/comments/https%3A%2F%2Fexample.org%2Ffoo%2F2345%3Ffoo%3Dbar%26baz%3Dxyz
However, before dispatching it to my application, the request URI always gets decoded by my server to
/comments/https://example.org/foo/2345?foo=bar&baz=xyz
This isn't working because the decoded resource name now has path delimiters and a query string in it causing routing in my API to get confused (my routing configuration assumes the request path contains /comments/ followed by a string).
I could double-encode them or using some other encoding scheme than URI encode, but then that would add complexity to the clients, which I'm trying to avoid.
I have two specific questions:
Is my URI design something I should continue working with or is there a better (best?) practice for doing what I'm trying to do?
I'm serving API requests with a Go process implemented using Martini 'microframework'. Is there something Go or Martini specific that I should do to make the URI-encoded resource names to stay encoded?
Perhaps a way to hint to the routing subsystem that the resource name is not just a string but a URL-encoded string?

I don't know about your url scheme for your application, but single % encoded values are valid in a url in place of the chars they represent, and should be decoded by the server, what you are seeing is what I would expect. If you need to pass url reserved characters as a value and not have them decoded as part of the url, you will need to double % encode them. It's a fairly common practice, the complexity added to the client & server will not be that much, and a short comment will do rightly.
In short, If you need to pass url chars, double % encode them, it's fine.

Related

Is it proper REST design to send all data for a PUT on the URI?

If I have very simple data to send to the server, is it okay to set up a URI scheme where all of it can be sent on the URI instead of in the body? For example, suppose I'm setting user preferences. I envision something like this:
PUT
/preferences/{setting-name}/{setting-value}
This allows my client code to be very simple because I can put the entirety of the message in the URI. Is that okay? Or should I be doing something more like:
PUT
/preferences/{setting-name}
...with the value in the content? Thanks!
Your first URI implies that ther is a (sub-)resource at
/preferences/{setting-name}/{setting-value}
But there is not resource, only a value. Using such an URI is not RESTful since it does not address a resource.
Your second URI is slightly better since it addresses a subresource {setting-name} of the preferences resource.
But I would prefer a third approach:
POST /preferences
Content-Type: application/json
{
"setting-name": "setting-value",
}
to put one preference. Note the usage of POST instead of PUT. PUT is generally interpreted as containing a complete representation of the resource in the request body. Such a request should overwrite all settings. Using POST is generally interpreted as overwriting only the setting specified in the body. Other settings are meant to be unchanged.
Note:
What makes me wonder is the front of your URI. Is there really only one set of preferences? Can and should all clients access the same set of preferences? If, for example, the preferences are user-based, you should use URIs like
/user/{user-id}/preferences/{setting-name}
to access the {setting-name} preference value of user {user-id}.

Pass rest resource output format in url

AFAIK every resource have a url in REST design. for example /user/28 is url of user with id equal to 28 and /users will return all users.
There are some way to represent output format of the resource:
passing a query parameter like format
specify it using extensions(changing /users url to /users.json to get the users in json format)
specifying the requested format(xml, json, xls, ...) by setting Accept http header.
I search the web and it seems the correct way is setting Accept header.
But if you want to have a http link (specified by href) to download list of users in xls format, you can't!Also if you want to download the xls by the browser, you will encounter many problems(you should use ajax so the xls should download using ajax and etc.)
If it is the best way, what is the solution for download link and if its not, which solution is better?
The Accept header is considered 'more correct', but there are plenty examples of all the options you mention. As far as I can tell, none of them is considered "bad". Personally, I'd say that you should honor and prefer the Accept header, but a format query parameter should override it, if present. The downside of the 'extension' method is that each format results in a different resource, which can get ugly.

Is it bad practice to allow specifying parameters in URL for POST

Should parameters for POST requests (elements of the resource being created) be allowed to be added to the URL as well as in the body?
For example, let say I have a POST to create a new user at
/user
With the full set of parameters name, email, etc... in the body of the request.
However, I've seen many API's would accept the values in either the body or URL parameters like this:
/user?name=foo&email=foo#bar.com
Is there any reason this second option, allowing the parameters in the URL is bad practice? Does it violate any component of REST?
The intent of a query parameter is to help identify the target resource for a request. The body of a POST should be used to specify instructions to the server.
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).
    -- RFC 3986 Section 3.4
The hierarchical path component and optional query component serve
as an identifier for a potential target resource within that origin
server's name space.
    -- RFC 7230 Section 2.7.1
The Udacity Web Development course, be Steve Huffman (the man behind Reddit), recommends only using POST requests to update server side data. Steve highlights why using GET parameters to do so can be problematic.

"/ " in a URL completely bypassing ASP Routing

One of my routes in an MVC project serves documents that have been uploaded.
For SEO and user friendliness purposes I want the document title to be included in the URL, the route will take the ID from the incoming URL, match it with the document then redirect to a URL with the filename appended to the ID. As document titles can have a wide variety of characters in the title including ones that are used to break up parameters the filename is a catchall parameter.
This works fine for almost all characters in the title including reserved ones such as "/" but when the title include the combination "/ " routing breaks. Not just in terms of not match this route but apparently bypassing the entirety of the application and returning a 404, I tried to use Phil Haack's RouteDebugger but that was also giving a 404 rather than catching the request.
My web.config has requestvalidation turned off and I can't seem to find anyway to get the application to catch the request.
I would recommend you filtering those character or you will have many headaches. Here's a function you might find interesting.

RESTful, efficient way to query List.contains(element)?

Given:
/images: list of all images
/images/{imageId}: specific image
/feed/{feedId}: potentially huge list of some images (not all of them)
How would you query if a particular feed contains a particular image without downloading the full list? Put another way, how would you check whether a resource state contains a component without downloading the entire state? The first thought that comes to mind is:
Alias /images/{imageId} to /feed/{feedId}/images/{imageId}
Clients would then issue HTTP GET against /feed/{feedId}/images/{id} to check for its existence. The downside I see with this approach is that it forces me to hard-code logic into the client for breaking down an image URI to its proprietary id, something that REST frowns upon. Ideally I should be using the opaque image URI. Another option is:
Issue HTTP GET against /feed/{feedId}?contains={imageURI} to check for existence
but that feels a lot closer to RPC than I'd like. Any ideas?
What's wrong with this?
HEAD /images/id
It's unclear what "feed" means, but assuming it contains resources, it'd be the same:
HEAD /feed/id
It's tricky to say without seeing some examples to provide context.
But you could just have clients call HEAD /feed/images/{imageURI} (assuming that you might need to encode the imageURI). The server would respond with the usual HEAD response, or with a 404 error if the resource doesn't exist. You'd need to code some logic on the server to understand the imageURI.
Then the client either uses the image meta info in the head, or gracefully handles the 404 error and does something else (depending on the application I guess)
There's nothing "un-RESTful" about:
/feed/{feedId}?contains={imageURI}[,{imageURI}]
It returns the subset as specified. The resource, /feed/{feedid}, is a list resource containing a list of images. How is the resource returned with the contains query any different?
The URI is unique, and returns the appropriate state from the application. Can't say anything about the caching semantics of the request, but they're identical to whatever the caching semantics are of the original /feed/{feedid}, it simply a subset.
Finally, there's nothing that says that there even exists a /feed/{feedid}/image/{imageURL}. If you want to work with the sub-resources at that level, then fine, but you're not required to. The list coming back will likely just be a list of direct image URLS, so where's the link describing the /feed/{feedid}/image/{imageURL} relationship? You were going to embed that in the payload, correct?
How about setting up a ImageQuery resource:
# Create a new query from form data where you could constrain results for a given feed.
# May or may not redirect to /image_queries/query_id.
POST /image_queries/
# Optional - view query results containing URIs to query resources.
GET /image_queries/query_id
This video demonstrates the idea using Rails.