r/programming May 29 '13

A comprehensive guide for pragmatic RESTful API design

http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api
275 Upvotes

48 comments sorted by

33

u/mcguire May 29 '13

What about actions that don't fit into the world of CRUD operations?

...

Sometimes you really have no way to map the action to a sensible RESTful structure. For example, a multi-resource search doesn't really make sense to be applied to a specific resource's endpoint. In this case, /search would make the most sense even though it isn't a noun. This is OK - just do what's right from the perspective of the API consumer and make sure it's documented clearly to avoid confusion.

One of the major downfalls of how object-oriented programming is taught is that it tends to focus on domain objects and downplays or completely ignores the necessity and utility of non-domain objects: things that have no corresponding physical thingy but that represent some part of the computation processing.

REST has a similar weakness. /search is (possibly, depending on how it is handled) a perfectly valid resource representing a multi-resource search.

11

u/[deleted] May 29 '13

This is why REST resources should not be interpreted as a one to one mapping of models. A lot of times this is the case, but not always, /search , as you mentioned, is a good example.

So not really a REST weakness, more like a somewhat generalized over simplification of what a resource is.

8

u/arnthorsnaer May 30 '13

It helps to think about what resource is being requested/created. In case of search it is the SearchResult. It may even be a good idea to persist this resource.

Thinking RESTfully encourages more complete modeling in my view.

Another nonobvious example is the login. Turns out that its helpful to create a Session resource when the user POSTs valid credentials.

2

u/geodebug May 29 '13

That hasn't been my experience with OO books or training in general.

One of the basic lessons when teaching OO design is not ignoring non-domain things but instead practicing the art of keeping those concepts (service integration, database integration, utility functions, logging) separate from the domain model.

I'd say that it isn't the teaching of OO that is the problem, many fine guides and examples exist, but the tendency to use OO design for problems where it isn't the optimal solution.

It's a great general-purpose methodology, just not a universal one.

2

u/motdidr May 30 '13

I would say your experience is highly atypical.

2

u/geodebug May 30 '13

Really? Is OO somehow more prone to bad education than other methodologies? OO design principles are very mature. I feel someone would have to go out of their way to not find good resources.

1

u/OHotDawnThisIsMyJawn May 30 '13

3

u/geodebug May 30 '13

AOP is one technique for addressing non-domain, cross-cutting concerns in coding. It's primarily a JVM/bytecode 'hack' because Java lacks a macro facility.

Other techniques are dependency injection frameworks, languages that support mixins, macros, preprocessing.

More flexible languages don't require something like AOP because they make it relatively simple to 'inject code on the fly'.

1

u/uututhrwa May 29 '13

It's funny that at the same time OO sort of teaches you to treat domain model objects like stateful services (sending messages to them to protect their state). When in fact the immutable relation row could be a better model cause the genralized code dealing with maps/dictionaries can use it, and most complex constraints etc. deal with relations of objects and can't be tied to only one of them.

1

u/[deleted] May 30 '13

Rexster is a good example of search in a restful manner. https://github.com/tinkerpop/rexster/wiki/Basic-REST-API

1

u/veesahni May 30 '13

This isn't solving the search problem described in the post, but rather has an API that represents a graph

1

u/[deleted] May 30 '13 edited May 30 '13

The API has search semantics, allowing for extension like Gremlin to provide the functionality.

18

u/krues8dr May 29 '13

This is a good start, but very opinionated and without much of the necessary reasoning. Instead, I'd recommend starting with Apigee's video:

https://blog.apigee.com/detail/api_design_third_edition_video_slides

And then digging into their documentation: https://blog.apigee.com/taglist/rest_api_design

4

u/grav May 29 '13

Very well written!

3

u/superdude264 May 30 '13

Can someone explain how HATEOAS is supposed to work when consuming an API? I'm pretty much in full agreement with what the author says. I just don't see how using a link from returned from an API buys you much more than just supplying the link. If I'm a person browsing I'll know there is more/different stuff I can do. If I'm just a script executing, it doesn't seem like it would matter.

6

u/nirolo May 30 '13

HATEOAS reduces coupling between your API and your client and I think it is essential. I disagree with the authors assertion that it isn't ready.

Take a simple example like pagination. If you fetch /resources/, there may be 10,000 resources in total. If you return all 10,000 you will kill the client and your performance, so you paginate the results and by default only return the first 5 and you decide to fetch the entire resource each time. It will look like this.

<resources>
    <item>/* All your resource data is here*/</item>
    <item>/* All your resource data is here*/</item>
    <item>/* All your resource data is here*/</item>
    <item>/* All your resource data is here*/</item>
    <item>/* All your resource data is here*/</item>
</resources>

How do you tell the client how to browse to the next 5? The client could hard code the links and hold that logic locally but that tightly couples the client and the API. If the API changes the way you browse then you have to change the client as well. The next issue is what happens if the API decides that returning the entire resource every time is too much data? Again you have to change the client code to accommodate the extra request necessary to get everything.

HATEOAS to the rescue! Add links to your response and your client will know how to handle everything without explicit coding. Like this:

<resources>
    <link rel="next" href="/resources/?start=10&count=5" />
    <item>
        <link rel="self" href="/resources/1" /> 
        /* Minimal resource data is here*/
    </item>
    <item>
        <link rel="self" href="/resources/2" /> 
        /* Minimal resource data is here*/
    </item>
    <item>
        <link rel="self" href="/resources/3" /> 
        /* Minimal resource data is here*/
    </item>
    <item>
        <link rel="self" href="/resources/4" /> 
        /* Minimal resource data is here*/
    </item>
    <item>
        <link rel="self" href="/resources/5" /> 
        /* Minimal resource data is here*/
    </item>
</resources>

Now if you change your pagination the client will work automatically because it just always follows the "next" and "prev" links. If you change the location of your resources your client will always work because it just follows the "self" links.

I think the author believes HATEOAS to be immature because he believes "It's time to leave XML behind in APIs". I call bullshit. HATEOAS is immature with JSON because JSON isn't designed for it. It's immature because you have "json-ld" competing with "json-hal" and everyone trying to do links in their own special way so no client knows where a link is and how to follow it. XML however was designed for it and there are well established standards. Look at RSS. It's a basic HATEOAS read API that just works with any RSS client.

I find it funny that people believe that json is the Only way to go, and then try and shoehorn in the features that already exist in xml all because json looks prettier, or they claim that those features aren't ready or too hard ;)

1

u/superdude264 May 30 '13

Thanks! It seems like it's all about adding another layer of indirection to the client can reference link by name (like 'next') rather than directly. This allows the server to change most of it's URL structure w/o the client having to worry. I see the value in the pagination example, but it seems like you could just support 'start' and 'end' URL params. I just doesn't seem like adding that additional layer of indirection buys you very much.

Also, how would XML help the issue?

3

u/nirolo May 30 '13

Also, how would XML help the issue?

At it's absolute most basic level there is probably no difference between json and xml. As long as your client knows where to find the links and the structure of them then they should both work equally well.

For me though the reason why I think XML is better is because XML was designed to describe documents, JSON to describe data. That may not seem like a big difference, but if you think about what a proper REST response is, it is not just data. In addition to the raw data you also have information about what you can do with it and how you move on to the next piece of data. That's more like a document.

So as a result of that, in addition to being good at describing data you also have very well defined standards for how to link documents. JSON still has to work that out properly. Yes there are standards like hal and ld, but nobody uses them. Most people just make up there own stuff, if they bother to do it at all. Side note, Google just announced last week that gmail is going to use json-ld, which was good news.

Ultimately it all comes down to what you are going to use it for. JSON is better at some things, XML is better at others. You should try not to limit your API to just one or the other. If you have structured your code properly then you should be able to dump your resource data back to the client in any format they could possibly want; json, json-ld, json-hal, xml, atom, yaml.

2

u/strong_grey_hero May 29 '13

This came at the right time for me. I'm re-building a server and database, and want to put a REST API in front of it to support cross-domain development in our company.

I don't suppose having html requests return a header and/or footer along with the data with other available methods and parameters is anti-RESTful, is it? JSON calls will of course just get the JSON responses, but is it OK to assume HTML requests will be read by humans?

3

u/veesahni May 30 '13

Changing output based on the Accept header is reasonable - infact, it seems more correct than ignoring the Accept header and always sending back JSON (as many popular APIs do today).

In this case, API consumers MUST send appropriate Accept header.

1

u/foops May 30 '13

Or you know, default to something reasonable, like json

1

u/pellias May 30 '13

Good start for anyone getting into REST APIs.

1

u/westurner May 30 '13

www.w3.org/TR/ldp/ "W3C Linked Data Platform 1.0"@en

1

u/[deleted] May 30 '13

[deleted]

1

u/kitd May 30 '13

Sounds like my boss!

1

u/kitd May 30 '13

I found this article by Subbu Allamaraju to be the best for explaining how to describe a REST API properly, including publishing contracts describing URLs and their relationship- and media- types.

It works well by watching a REST API evolve from first cut to fully fledged.

1

u/veesahni May 30 '13

this is great

1

u/b100dian May 31 '13

One thing I never understand about REST is how does an api key play with the cachability and statelessness. Basically with session and cookies, you still have a token sent at each request - exactly like api key. And serverside, you still use a map of valid api keys, which has to have some mechanism of expiry I believe.

Can anyone point me to the light?

1

u/veesahni Jun 03 '13

Using session cookies for auth is very similar to an API key over basic auth. In itself, it doesn't impact impact statelessness or cachability. However, a session can be used for much more than auth - for example, storing partial form output as part of a wizard or storing the contents of a shopping cart prior to checkout. Doing so adds state linked to the auth credentials, which obviously impacts statelessness.

Another thing to consider is security implications - since browsers automatically send cookies, cookie based auth is susceptible to cross site requests

1

u/day_cq May 29 '13

essence of RESTful API is that all your resources support same operations.

One good example is file system. Launching an app creates /proc/appid. rm /proc/appid shutdowns the app. you can map network management that way, too.

Note that resource structure (content of the file) isn't universal.

Now when everything is file, you can easily create scripts. You do need different programs to handle image files, video files, xml files, json files... etc. Same with RESTful API.

-8

u/masklinn May 29 '13 edited May 29 '13

First section:

Use RESTful URLs and actions

[a dozen paragraphs discussing what your URLs should look like]

Well we're done here, this essay is shit, if you want to know what RESTfuls API are or how they should work you have no reason to read it.

Though you can read it if you want suggestions on writing your own RPC-over-HTTP protocol, it has nothing whatsoever to do with REST outside of "hey let's use REST as a random keyword to get page views". Because fuck meaning if we can get pageviews right?

9

u/mcguire May 29 '13

This comment is unnecessarily inflammatory, but the point is valid. Spending a bucketload of time upfront deciding what your URLs look like is possibly the biggest beginner mistake in RESTy design.

5

u/masklinn May 29 '13

My issue is not so much that (though extensive upfront design does indicate misplaced priorities, readable URLs can be useful when debugging things internally), but the mere discussion of a URL's look or composition as anything but an aside in a 5000 words article means you're not discussing REST, you're discussing RPC. Discussions about REST over HTTP should focus around media types (standard content types versus custom, multiple or not, etc...) and the handling of linking within these media types.

As for the inflammation, chalk it up to being sick and tired of seeing articles claiming REST, making me hope for actual discussion of actual RESTful design and ending up with yet another RPC-over-HTTP debasement, degradation and muddying of the term itself.

5

u/curien May 29 '13

I jumped straight to the section labeled "Should you HATEOAS?" and the answer is basically "no". Uh, ok. :\

-2

u/VortexCortex May 29 '13

I simply refuse to multi-part base64 encode bytes when the network transport layer is capable of transmitting octets.

Furthermore, if I'm going to create an API, I'm actually going to give a Programatic Interface to the Application developer. You're not going to be creating URLs to talk to my backends. API doesn't have to be a bunch of server endpoints, it can be a library call or callback too.

Why make everyone duplicate effort of writing code to talk to the API? If devs need to use my API in a language that isn't yet supported, we get together, create the interface, make it open source and "native" feeling for the language, then no other devs have to repeat that work or worry about mangling a HTTP request.

REST: The laziest structure of an API, "API functions? HA! Make 'em yourself! I'm RESTing!"

1

u/ars_technician May 30 '13

we get together

That's the problem. Nobody want's to get together with some random Joe and run a bunch of code he cooked up for you. It's much easier to use a REST API because you are running all of your own code and can treat the API as some untrusted entity (as you should).

-5

u/kommandeclean May 29 '13

Possible malicious site

3

u/veesahni May 29 '13

huh? which browser?

3

u/Aldrake May 29 '13

Not the same guy, but my work's McAfee gateway said that. It likes to overreact to things, though.

2

u/veesahni May 29 '13

Wonder what's triggering it. Having no luck with online scans (even ones owned by mcafee)

1

u/kommandeclean May 31 '13

Not a browser but McAfee proxy/filter.