Back to Blog
Sep 4th, 2013

What the Rest?

Edit
What the Rest?

Tip

See the follow-up post called REST Revisited that talks about the key things we learned from this.

When I talked recently about being collaborative and open, I mentioned that I was weeks into research around building RESTful API's. I've been like Luke training on Dagobah, except replace Jedi powers with REST and Yoda with the Internet, RFCs and dozens of blog posts. And despite everything, my mind is clouded. When it comes to new tech, sometimes the more you learn about the pieces, the less you can see how they could ever fit together. This post is an experiment to see if we can fix that.

REST is as deep as the rabbit hole, with varied approaches, undefined best-practices, and flamewars along the way. Should I use custom hypermedia types or something like HAL or JSON-LD? Should I implement OPTIONS, and if so, should it tell me only what methods to use or much more? What role should the API documentation play and what information should be described inside the API itself? How do custom verbs like banning a user or linking to a friend look?

Tip

I owe a big thanks to Luke Stokes and his team's WIP API for FoxyCart, which I'll bring up in this post. Luke let me bother him with questions (repeatedly) and was wonderful about it.

Eventually, best-practices will rise to the surface. But I (and maybe you) want to build a high-quality "REST" API right now. Curiously, HATEOAS - the missing RESTful piece for many APIs - has made things more difficult for me so far. The idea is beautiful: return links in your API to help the client know what to do next. But links, which are basically a URL with a "rel", only tell part of the story. What methods does that link support? What fields should I send to it? And where should all this information live?

In the next sections, I'll say some things about REST that are just wrong. And hopefully, I'll be corrected. I'll pour out my RESTful heart, and invite you all to crush it and build it back up. I've heard that the Internet is good at correcting people, so I thought, why not tap into that? :).

By the end, I hope to have one, good, well-defined path that can be written up and shared openly.

HATEOAS: What you can do next?

When I get a response from a RESTful API, it should contain links. Like on a webpage, these tell me what I might do next (i.e. what actions I can take).

As I understand it, it's not exactly correct to say that links are links to resources. Of course a link has a URI, and each URI is an address to a resource, but you could have multiple hyperlinks to the same URI. For example, imagine there are multiple actions I can take on that resource. Suppose that when we go to the homepage of our API it returns the following links (I'm using HAL to represent the links, but that's not important):

{
  "_links": {
    "self": {
      "href": "/"
    },
    "http://api.example.com/rels/users": {
      "href": "http://api.example.com/users",
      "title": "Users in the system"
    },
    "http://api.example.com/rels/users_reinvite": {
      "href": "http://api.example.com/users",
      "title": "Re-invite unregistered users to the system"
    },
  },
  "...": "... other stuff ..."
}

In this case, we have 2 different links (actions) but each link points to the same resource. This is because there are 2 actions that can be taken on that resource. This is my understanding of links versus resources, a distinction which is important because it means that a link is much more than just a URI.

Tip

I recommend using the HAL Browser for the FoxyCart API if you want to see how this really looks for an API.

We don't know exactly what to do with those links yet, but that's next.

Exactly how these links look depends on your hypermedia type (e.g. HAL something custom, etc), but a link has the following information:

  1. A URI;
  2. A rel to explain the significance of this link;
  3. (optional) A type, which defines the hypermedia type to be returned by the link;
  4. (optional) A nice human title for the link;

In a browser, we click links (i.e. GET) or submit a form (i.e. POST). The form contains the fields we need to send right inside of it and there's an web-wide standard of sending that data in a certain format (i.e. application/x-www-form-urlencoded). So when we're using a browser, each link contains all the information needed to follow it.

But that's not true at all with an API. We need more information than we have from simply looking at the link, which I'll call:

  1. What HTTP methods can I use with this link?
  2. What fields should I send if I'm POST'ing/PUT'ing?
  3. How should I encode that data in the request (e.g. application/json, application/x-www-form-urlencoded, etc)?
  4. What media type(s) should I expect back from the response?

HATEOAS tells us to use these links to determine what our next step, or action is (they induce application flow). In the HTTP world, they should tell us what possible HTTP requests we can take next.

So if this information isn't found in the hyperlinks, where does it live? Where can an API client find these details and how does she know to look there? This is at the heart of the trouble I have in understanding RESTful APIs.

Tip

Some hypermedia formats like JSON-LD seem to have a more sophisticated method where "link data" is exposed that answers some or all of these questions. I'm very interested in this, but first I want to know how this should look in simpler cases, like when using HAL. If people are using HAL, then there should be a "right" place to define this information.

Finding the Missing Pieces to make the next Request

Your API also needs to choose how its hypermedia type(s) look like. Will each link have its own type (e.g. application/vnd.com.users+xml) or will you use one hypermedia type like HAL?

Right now, we're missing 4 pieces of information before we can really make the next request. In REST, you often read that the only thing you should need to document is your hypermedia types. In that model, does every link have its own hypermedia type? And do the docs for that hypermedia type really tell us what HTTP methods can be used and what fields can be POST'ed? That would seem odd, especially because the data is not sent (e.g. POST'ed) using the hypermedia type. Usually data is sent with something simpler like application/json, and the special hypermedia is only used in the response.

So let's look at the 2 approaches (custom hypermedia type versus HAL) and try to see how a client would answer the 4 questions standing between us and the next API request:

+--------------+-------------------------------------------+--------------------------------------+ | | Custom hypermedia type | HAL (or similar) | +--------------+-------------------------------------------+--------------------------------------+ | HTTP Methods | Find docs based on the hypermedia type?? | Find docs based on the link rel | +--------------+-------------------------------------------+--------------------------------------+ | Fields | Find docs based on the hypermedia type?? | Find docs based on the link rel | +--------------+-------------------------------------------+--------------------------------------+ | Request | Find docs based on the hypermedia type?? | Find docs based on the link rel | | encoding | | | +--------------+-------------------------------------------+--------------------------------------+ | Response | Read the link type attribute | Assume HAL | | media type | | | +--------------+-------------------------------------------+--------------------------------------+

Tip

The rel could literally be a URL to the documentation. FoxyCart uses this (e.g. https://api.foxycart.com/rels/users).

It seems that both methods will probably rely on some external documentation. This is known as "out-of-band information", which we shouldn't need in theory. But I'd argue that creating an API that's fully self-describing is still very hard, and quite possibly not worth it.

Some pieces of information could probably be answered globally for your API (e.g. Request encoding). Very literally, you might just say on the homepage of your docs that all endpoints support application/json and application/x-www-form-urlencoded.

But usually, we will need to look up a specific API docs page for each link. For a custom hypermedia approach, the docs seem to be for each hypermedia type (right?, wrong?). For HAL, since we only have one hypermedia type, we rely entirely on the link rel. This could all totally be wrong, but if it is, then how should the client be answering our 4 questions for each link? If we have docs, how do they know which doc to look at for each link?

Value in OPTIONS?

What if we made an OPTIONS request to /users? This actually seems very unhelpful, as the OPTIONS is for a single URI, which could actually have multiple links to it. The OPTIONS response may say we can POST, but how would a client know what to POST? In our example, there will be 2 POST actions (one for creating a new user resource and another for "re-inviting" users), each which has its own documentation on how the fields should look.

OPTIONS may be helpful if it returns the links that I would receive if I made a GET request to the resource. In our example, we'd have:

{
  "_links": {
    "self": {
      "href": "http://api.example.com/users",
      "title": "Users in the system"
    },
    "http://api.example.com/rels/users_reinvite": {
      "href": "http://api.example.com/users",
      "title": "Re-invite unregistered users to the system"
    },
    
    "...": "... other links, like first, prev, next, last ..."
  },
  "...": "... other stuff, like embedded users ..."
}

Of course, I could just make a GET for this information. So is there value in OPTIONS?

Problems: When I have only a URI

One important consequence about a REST API is that we're not really supposed to start with (i.e. bookmark) a URI. In fact, with just a URI, we don't really have enough information to know what to do with it.

Tip

In this section, I'll look only at HAL. If you're using a custom hypermedia type, then I think you also have a problem. If you only have the URI, you don't know what Accept header to use in your request nor would you know really how to process the response. You simply don't know what hypermedia type you'll get back.

For example, if I know nothing about /users and I make a GET request, I get back these 2 links (among other things):

{
  "_links": {
    "self": {
      "href": "http://api.example.com/users",
      "title": "Users in the system"
    },
    "http://api.example.com/rels/users_reinvite": {
      "href": "http://api.example.com/users",
      "title": "Re-invite unregistered users to the system"
    },
    
    "...": "... other links, like first, prev, next, last ..."
  },
  "...": "... other stuff, like embedded users ..."
}

Notice self, which is a standard IANA Link Relation, but which no longer includes the helpful http://api.example.com/rels/users "rel". If the rel is the key to finding the docs, we're stuck.

Of course, according to the rules, we shouldn't be hardcoding URIs', we should always start back on the homepage and follow the link, with its nice rel.

Tip

DHH famously argues against this idea that an API client would always start from the homepage and dynamically crawl instead of hardcoding URLs (Getting hyper about hypermedia APIs). I'm pretty sure this pissed a lot of people off, but I think he makes a lot of sense.

But this scenario does show up during normal client-server interaction in at least two places:

  1. After POST'ing to create a new resource, the location header gives us the URI to the resource, but without a rel;

  1. When GET'ing a collection resource, the embedded children don't have a specific rel value (they have self):
{
  "_embedded": {
    "users": [
      {
        "username": "weaverryan",
        "_links": {
          "self": {
            "href": "http://api.example.com/user/weaverryan",
            "title": "Users in the system"
          },
          "...": "... other links ..."
        }
      },
      "... other users ..."
    ]
  },
  "...": "... other stuff, links, data, etc ..."
}

In both cases, we can GET the resource, but we're never given the pointer (rel in HAL) to the docs, which answer our questions. I need some "in-band" information that tells me where to find ("out-of-band") the API documentation. Said more simply, if I'm presented with a link to this user, how should our client know what to do with it?

FoxyCart's solution is to include this information in the "originating" docs. In the 2 scenarios above, I'm POST'ing and GET'ing to /users and we already have its rel (http://api.example.com/users). This means we also have its docs. On that page, the documentation from http://api.example.com/user (the "rel" for the new resource) could be embedded (see "Embedded Resource: user" at https://api.foxycart.com/rels/users).

Is there a better way? How should the API client know what to do with this new resource? What can be safely assumed?

Opinions, Experiences, Please!

Again, a huge thanks to Luke Stokes and FoxyCart for pioneering so much of this and answering my questions. If you're someone who's been in the trenches with REST, comment, enlighten and correct me please! Anything we accomplish here will ultimately turn into code, a script (both of which will be available publicly) and a screencast.

But one more thought! The further I get into REST, the more rules I see. Things like hypermedia (linking to what I can do next) seem very pragmatic and wonderful. But immediately after, I find myself (as a client) having a difficult time navigating a RESTful API and knowing where to find the docs (whether those docs are part of the API or externally). I want to be able to leverage all the great ideas behind REST, but not be constrained by them. At the end of the day, we need an API that I can build and that our friendly API client can understand quickly. In some ways, then, the path of DHH (Getting hyper about hypermedia APIs) does make sense: use what's good, leave what's complex, break some rules, and move forward.

But, maybe I'm just missing a few, final, beautiful pieces to get out of the swamp and up to blissful RESTland.

Thanks!

18 Comments

Sort By
Login or Register to join the conversation
Default user avatar tgalopin 6 years ago

I'm not a fan of the documentation directly inside of the API. I mean, this idea is great because you describe you API to users, but this is not the good place to do it.

Did you hear about Swagger ? It describes all you talked about (allowed methods, prec/next pages, titles, descriptions, ressources, even models you can get, ...), but externally (and with some great tools as Swagger-UI it's easy to generate awesome UI documentation).

The only case I think an internal link to another resource is useful is in the case of pagination : you tell to users where if the first/previous/next/last page. However, in most case, I prefer an external doc. That does not mean developpers shouldn't follow a given convention, just that the API is not the place for the documentation.

If you don't want to search for the external documentation, it's really easy to return a key with the documentation location on the homepage ("/").

| Reply |
Default user avatar mikekelly85 tgalopin 6 years ago

Hi Titouan, what are the actual reasons you feel that making the documentation accessible from the API like this is not a good idea?

1 | Reply |
Default user avatar tgalopin mikekelly85 6 years ago edited

I've two main reason for this :

- separation of concerns : the API is not the doc, the doc is not the API. By definition, it's not the role of the API to be a doc. You can (and should) use a logical organization that follow conventions, but you shouldn't describe that convention in the API but in an external doc ;

- as mikekelly85 said, it's redundant. If you follow a convention (for instance the REST convention), you don't have to specify such links or docs in the API. The client is able to guess the next page using this convention. The client is able to guess which page is what. And finally, using some tools like Swagger, the client can easily know the format of the response returned by the API ;

| Reply |
Default user avatar mikekelly85 tgalopin 6 years ago

Surely the concerns are actually separated, though?

The docs are available indirectly by following the link relation to its documentation, they are not inline in the json itself. What are the types of problem you believe this causes?

Also, I'm not sure what you mean by "REST conventions". I suspect you might be referring to conventions around URL patterns? You can promote that technique if you like, but it is nothing to do with REST.

Why would you want to have the client guess where the documentation is when there are techniques that can relieve you and your clients from this brittle form of coupling?

66 | Reply |
Default user avatar tgalopin mikekelly85 6 years ago edited

I don't agree with you on the fact that concerns are separated. mikekelly85 talks in his article about available methods, title that describes links and requests/responses format. He implements in his examples only titles, but he talked about the rest.

That's where I don't agree with the organization, and just here. The concept of links seems really nice, but in my opinion, a bit of URIs organization would be efficient enough. A documentation describing title, allowed methods, responses/requests formats should be external.

About the REST convention, it's always the same problem : the REST definition is not the same for everyone. I consider REST include URI formats, but apparently you don't. That's not the point, the name of the convention doesn't matter. The point is that if every developper followed a given convention that fix URIs format, it should be enough clear for clients to use it. And the rest of the doc (titles, explainations, formatting, ...) should be external.

It seems obvious that a convention for such API problems should exists, and I'm happy to see the work of weaverryan and mikekelly85 about it. I just don't agree on a small detail of organization, the global idea is cool :) .

(and for the last point, I don't want the client to guess where the doc is : I give him the location of the external doc from the homepage of the API)

EDIT : I explain my personnal reflexion in the answer to Luke Stokes : http://knpuniversity.com/bl...

| Reply |

Hey tgalopin

Awesome! This is a bit what I was expecting (and hoping) for - that at least some people would agree that external documentation is still needed and normal. When you're creating an API, planning out how your docs will look and how a client will know where to find them is at least as important as the API itself. This makes me think even more about using links as an "extra" nice pointer to help the client, but to have API docs for each resource/URI like a traditional API, which would be nice and easy to find.

Someone might still come and convince me otherwise, but what you're saying feels right to me.

I have heard of Swagger, but haven't used it yet - so thanks for the reminder! Since docs are key (as is finding a "best practice" for all of this), letting Swagger "lead" on that front is probably a great idea.

Thanks for the response!

| Reply |
Default user avatar Luke Stokes tgalopin 6 years ago

My concern with Swagger (and similar API documentation systems I've seen), is they focus on what can be done per URI, instead of per link relationship. For those taking the HATEOAS approach, URIs can change all the time at the server's discretion. I'm exploring a different approach that links documentation to the link relationships and not the URIs: https://api-sandbox.foxycar...

| Reply |

As I got it, what you want to do is to not use URIs but links, to avoid future problems with clients as they use links names and not URIs (and you can change URI easily as clients does not use it). Isn't it ?

But what is an URI ? An "Uniform Resource Identifier" (thanks Wikipedia :) ). I think the concept itself resolve the problem : with some organization (some conventions), you should have URIs like these, for instance :

http://api.example.org/users -> list of users (pagination using GET parameter)
http://api.example.org/users/1 -> user 1 and its informations
http://api.example.org/user... -> POST to edit user 1

In fact, using a given logical organization threw your URIs, it's really easy, using the first one (/users) to guess the next ones (/users/1, /users/1/edit). It does not need to be specified in the API : it's REST itself that describe this convention.

My point is that you shouldn't need to do links like these. If the API is RESTful, you can create a flexible client library which use only dynamic pathes, based on the first ones (if you really want to be completely flexible, you can specifiy these root URIs in the homepage /).

Swagger has this point of view too. You have to declare resources (root URIs), operations (sub URIs) and finally models. The concept of links is just the same, but following your own convention. Isn't it better to use a global one : REST ?

| Reply |
Default user avatar Luke Stokes tgalopin 6 years ago

When you say REST or RESTful, what do you mean? Do you mean a URL hierarchy which is organized in a logical manner? Do you mean Roy Fielding's definition?

...and this is where things get confusing. :) I like the term Hypermedia API to get around some of the confusion, but it only gets us part of the way there.

I think what you're describing is URL templates, which many people also really like. I probably should look at Swagger more closely, but if there are pre-defined url templates for things like edit, what about non-CRUD operations? Each API may have its own conventions and custom operations. I also prefer to have the HTTP methods define what is going on more than the human-readable url (can I GET /users/1/edit as an example?).

There are a lot of great discussions about this stuff in the API Craft Google Group. I haven't been as active there recently, but I've learned a LOT from that great community. Also, I'm looking forward to RESTfest in less than two weeks. Last year was fantastic.

| Reply |

As you said, the REST definition is not the same for everyone :) . Indeed I described something like URIs templates.

The point is not about Swagger, I just quoted it because it follows the rules I talked about (and yes, obviously, you can define your own operations). My reflexion is more this :

Is it the role of the API to describe links (title, methods, formats, ...) ? IMO no. Therefore using your concept of links, we can remove from the API the title of a link, the request required format or anything else that will be in the external doc.

What's left ? The URI. In fact if we externalize the documentation following a separation of concerns we just match a link to a URI.

If we do that, why do we need to give users these links ? We have a consistent API, don't we ? So our root URIs match our sub URIs and we can follow a convention that let users guess our API URIs without links.

Am I enough clear about my idea ? I'm not sure to be, ask me if you don't get something.

| Reply |

I think that tgalopin and tgalopin have debated towards an interesting, simple questions, which is:

What is the value in providing a "rel" for a link and using it as the documentation pointer instead of the URL?

I'm playing devil's advocate with this question. There's probably an answer, but I don't see it.

With HATOEAS, we use rel's and the client should code against the significance of those rel's. URI's could change, but the importance of rel's should not change, because I've coded things in my application based on the API's rel's. This especially makes sense for things like the pagination links (next, prev, etc) because I instantly understand what these links (to the same resource I'm looking at now) mean.

But when I'm linking to another resource (e.g. I'm on a user resource, linking to that user's "photos"), why include a rel (e.g. http://api.example.com/rels... If the purpose of rel is *only* to point to the location of the documentation, then why not just leave the rel off and use the resource URL (e.g. /users/weaverryan/photos) as the way that I find the documentation (e.g. I go to the docs homepage and look for a link to the docs for (/users/{username}/photos)? As a bonus, if there are any custom verbs on the resource, I'll find them all on that one page, versus spread across several links (and docs pages).

What does the rel give us beyond just pointing to the docs that makes it worth using instead of the URL?

| Reply |
Default user avatar Luke Stokes 6 years ago

Great post, Ryan! I'm glad our email conversations were helpful. It sounds like you're about to engage in some of the reasons people prefer Collection+JSON or Siren over HAL because those formats are more explicit about which properties are valid per resource by including the concept of forms and actions. Some see this as an excellent solution to the concerns you've raised. Others see it as moving back towards SOAP and dynamically generated clients which become brittle and/or can't evolve independently from the server (and vise versa).

I see it as different strokes for different folks. Until the AI-powered Hypermedia robot overloads take over humanity, programmers will still have to write client code based on what their brains understand and interpret from the documentation and server responses. In my mind, that's done once at the time of client development, and then left alone until they want to upgrade or take advantage of new affordances the server provides. To include that in every response (especially in mobile applications), seems redundant and not quite as useful to me. That's just my current opinion, and it's definitely changing the more I learn.

I'll probably read through this a few more times and hopefully offer some more input.

| Reply |

Hi Raul!

Yes, we are *definitely* on the same page approaching the same problems, so I'm really happy to hear from you! A few things:

1) I guess I like the `X-Location-Rel` idea - it gives us exactly the information we're missing. Though, I'm surprised that we both hit this problem and I can't find anyone else talking about this. I don't quite understand the second possible solution (URL with docs and resource), but that might not matter because the header makes nice sense.

2) I'm really glad you brought up the HTTP verbs, because they are a *huge* pain. As soon as we get out of the CRUD actions, there seems to be little direction on how the endpoints should look. Your solution with server reboots is clever, but it's almost lucky. If server reboots were something that happened instantly, then it would no longer be useful to think about them as a pile of "tasks", and the endpoint would make less sense. Really, we're changing the "resource state" of the "/server/myserver" resource. So how should we do that? For the most part, it seems that POST'ing to the resource is correct.

We now would have 2 different links (one with a rel for the main CRUD actions and another rel describing our POST reboot). If you do this, then something in the POST body should probably tell the server that we're requesting a reboot (because later, we might have a second POST on that resource, e.g. for a "shutdown"). That seems a little RPC to me (like your PATCH example).

FOSRestBundle's route generation seems to propose doing a PATCH "/server/myserver/restart" (see: https://github.com/FriendsO.... This *might* make sense - the "restart" now looks like a sub-resource or "partial resource" on the server (almost like "restart" is a field on the resource that we're editing).

Both of these things seems really basic, but without clear answers. I'm hoping to find answers to these, but for now, you may just need to choose one solution then run as fast as you can assuming you're perfectly correct. The world will be better when we have more HATEOAS'esque API's, so that we can scrutinize and learn from them.

Thanks!

| Reply |
Default user avatar Larry Garfield 6 years ago

Hey Ryan. I think the problem is that the "self-discovering API" concept of REST/Hypermedia is a bit over-sold.

It's not reasonable to expect a client to see a new rel it doesn't understand and somehow derive meaning from it. However, if it sees a rel that it *does* understand, in concept, then it should be able to know what it means and figure out logically what it means in relation to the source of the link.

To use the example you already cited, a client that knows what "next" and "prev" mean can automatically "know" what it should do with those links if it sees them on a resource. If it sees "bob", though, it doesn't know what "bob" means. It should therefore ignore it until a human comes along and programs in the Meaning of Bob. Documentation is for a human.

Using a URI for non-standardized rels is simply for namespacing to avoid collisions. It's not required that it point to human-readable documentation, IIRC. Tools like the HAL browser make it really convenient to setup documentation pages that are accessible from the rels (via curies), but that's not strictly a requirement of RESTfulness.

As far as mime types, remember that a given resource should conceptually exist independently of a representation. In concept, your resource SHOULD be available in some representation the client asks for; that's what content negotiation is all about. "I can take application/hal+json, or just application/json, or if all else fails text". The server figures out the best it can do and then returns that, and in the response says what it's giving back. (It's not, in fact, strictly required by the HTTP spec that the server return one of the requested formats. That's especially important for error handling where you may return vnd.error or api-problem instead of HAL or Collection or whatever.) In practice, "whatever format you're using, keep using" seems like the logical default.

For methods, again this is where the purity of REST breaks down or gets over-sold, IMO. In theory, GET, PUT, and DELETE have very clear specific meanings; if you can't map something to one of those meanings, you shouldn't offer that. GET should likely work on just about anything; PUT and DELETE only sometimes. POST is the "generic other stuff". I think I've seen Fielding argue elsewhere "if it doesn't make sense as a normal RESTful operation, POST as a catch-all is totally fine. Just don't then call it RESTful."

A lot of things make sense as a REST-ish API, not as RESTful API. Sometimes forcing greater purity doesn't actually buy you much. Eg, "POST /server/shutdown some-password" is not Truly RESTful(tm), but I don't see any reason to over-engineer it to be.

Cheers.

| Reply |

Hi Larry!

I'm very happy to see your comment here! Part of the journey through REST has been to transition from "I don't know anything" to "I know some things, but others know how to do things correctly" and then finally arriving to "I know enough, nobody has the perfect answers, and it's ok for me to make *good* guesses about how to build my REST(ish) API" :). Hearing you and others repeat things about the "over-hyped" self-discovering API and the difficulty of finding the right spot for custom methods reinforces that big time.

For those that read this later, I want to repeat a few things you said that I think are particularly important:

1) If a client sees a "rel" that it does not understand, we don't expect it to derive meaning from it. A human will need to come, read the documentation, the give that "rel" meaning in the client app. Beautiful! But when a client *does* see a rel it understands, it knows what it can do with it. So a rel isn't a magic bullet, it's just the anchor your application uses to say "I know what to do with this" or "I've never seen this before, call the humans!". In older APIs, this would be the URI. Now, it's the rel.

2) I did talk about the API as if there were only one representation, but it is important to remember (at least in theory) that you may have 5 representations (application/hal+json, application/json, etc) of the same resource. Also, I didn't talk about validation at all, but I think it's good that you point out that we *may* not get back a mime type that the client asked for. Perhaps that's not a perfect scenario, but as long as there is a contract that says "on validation errors, we're going to return `vnd.error`", then it *feels* ok. And by contract, I mean something that the human read, like the homepage of the API docs :).

3) Custom methods! Bah! I have also gotten the impression that POST is sort of the "catch-all". I think I'll mostly run with that. However, I can see in PHP code that it will smell a little odd. For example, I may have 2 custom methods on the same resource. Both are POST. They are only differ in the contents of the request body. So, I'll parse the PHP body in the controller to see what we are actually doing. Perhaps there's an "action" key in the request body. It's a little ugly, but doable. At the same time, it smells strongly of RPC :). At least it's only on a POST, so it doesn't affect HTTP caching.

4) And finally, there is probably not perfect REST API. So don't call it REST, make educated decisions, bend some rules, and ship it.

Cheers!

| Reply |
Default user avatar Larry Garfield weaverryan 6 years ago

Well, I wouldn't suggest forking a POST request like that. That is a code smell, because you have a single operation that's doing 2 things.

I see two ways to think about POST requests, which are not entirely mutually exclusive.

1) The RESTy way: A URI represents a Processing Resource. You POST data to it, which means you're asking the resource to Process the data you're providing.

2) The RPC way: A URI represents a function call. You call it with parameters, it does its thing, and returns a result. The function call should follow all of the same rules as a normal in-process function call.

Very similar result, slightly different approach. But in both cases, don't fork things. :-)

URIs are cheap, so just add more of them. Don't use POST /article/1 {publish:1} as an operation just to save a URI, especially if you also try to shoe-horn POST /article/1 {promote: 1} into it.

Instead, do one of the following:

1) The RESTful way: PUT /article/1/published 1 (Write the value true to the article's published sub-resource.) You can also then unpublish with PUT /article/1/published 0

2) The RPC way: POST /articles/publish {aid: 1} (Call the "publish an article" function with the value of the article ID.)

And then a corresponding "promote" using the same model.

Not everything can be fit into a RESTful model, but a surprising amount can. The question is "can I phrase this in terms of CRUD?" If so, the RESTful approach works well. If not, or if it's super-awkward, eh, don't lose sleep over it and RPC it.

| Reply |

Thanks Larry - you responded to the exact part I was hoping you would - this clarifies this last ugly part quite a bit!

| Reply |

Hey Raul!

About the 201 redirect issue with the "rel", there brought up a good point last night at the Nashville PHP meetup. At first, he really liked your solution of adding the `X-Location-Rel` header. But then he asked, "If I'm POST'ing to create this user resource, don't I *know* what I'm creating?". In other words, I will need to have read the docs on the "users" collection rel (e.g. "api.servergrove.com/rels/users") which would tell me what the POST body should look like for creating a user resource AND it should tell me the main "rel" for that (user) resource. We are very used to the idea that the API will always give us the "rel", which we use as the key to finding the documentation. But in theory, it doesn't need to be this way.

But I don't think that adding the header is a bad idea, but I did think it was valid to point out that we would never have been able to create user resource without reading the "users" rel documentation, which should tell us what to expect back. However, in some ways, the 201 response with the "Location" header *feels* just like a link to me, since it tells me what I can do next. And since links in Hal contains a URI *and* a rel, it also makes sense that this link would contain a URI (the Location header) and a rel (`X-Location-Rel`).

Just food for thought :)

| Reply |

Delete comment?

Share this comment

astronaut with balloons in space

"Houston: no signs of life"
Start the conversation!