Hacker News new | ask | show | jobs
by caseysoftware 3574 days ago
This depends on your data model.

If "status" is just a property on the accounts resource and doesn't have further meaning, I would tend to agree with you.

If "close" is an action or activity that acts upon an accounts resource, then his approach makes sense.

Since the context is an account that we "need to close," I would assume the author is talking about something more complex than a database field. It's probably a workflow that initiates other actions and workflows, maybe even requiring additional review. I'd want to see/understand the requirements more fully before I started down either path.

3 comments

REST is just a representation of the underlying data. What does it matter if "status" is a database field or not?

More specifically, it shouldn't have to matter to consumers. Because of the way REST and HTTP work, clients intuitively understand retrieving and modifying resources (via GET, POST, PUT, PATCH and DELETE). But they don't understand interacting with special-purpose endpoints (POST always implies "make a new thing" so it's weird in this context).

Your consumers should not have to learn weird idiosyncrasies in your API because you let your data model bleed into the interface.

No, REST and HTTP are implementation details of the technology.

An API is a representation of business workflows and processes. The more accurately you describe or map those to the real world processes, the better your and your consumers' understanding will be.

What if 'status' isn't a column in the account database? What if closed_accounts is a join table or something else? Then wouldn't adding a /close route be hiding idiosyncrasies in your data model, not the other way around?

It seems like we spend a lot of time designing object relations that map a domain, but maybe not so much mapping domain-specific actions.

Or would you consider all of the above bad practice?

This doesn't really matter. What you'll end up exposing via your API is your use case! Does your system allow for an account to be closed? Awesome! So let the client know how to do it.

If you're speaking HTML it can be as simple as:

  <form action="/close-account?acc_number=12345" method="POST">
    <button>Close Account</button>
  </form>
Or even:

  <form action="/close-account" method="POST">
    <input type="hidden" name="acc_number" value="12345">
    <button>Close Account</button>
  </form>
If you're speaking Siren (https://github.com/kevinswiber/siren):

  {
    "actions": [
      {
        "title": "Close Account",
        "method": "POST",
        "href": "/close-account",
        "type": "application/x-www-form-urlencoded",
        "fields": [
          { "name": "acc_number", "type": "hidden", "value": "12345" }
        ]
      }
    ]
  }
> What if 'status' isn't a column in the account database? What if closed_accounts is a join table or something else? Then wouldn't adding a /close route be hiding idiosyncrasies in your data model, not the other way around?

So what? REST is an API [0]. It's the public interface you expose. What you do behind the scene in your data model is, or should be, irrelevant to the API. Sometimes you'll map your data model practically one-to-one to the REST API, but there are times when I do significant logic in controllers before mapping the result of that logic to a resource. As long as the API is resource oriented and follows good REST practices, it's all good.

0. OK, REST is one way to expose an API, since the wording I used is not amenable to some people.

> REST is an API.

No, REST is an architectural style.

> No, REST is an architectural style.

For APIs. But yes, we can argue semantics now. My point is, REST is a way to expose an API.

> If "close" is an action or activity that acts upon an accounts resource, then his approach makes sense.

Right. Particularly, if a closure request is a thing that has its own status, identity, and associated data elements, which one might wish to examine and interact with (and, while its possible that such interaction might not be possible for external users with privileges only on their own accounts, it might well be possible for internal administrative users), then it makes sense as a resource, rather than a data element buried in representations of another resource.

Without full behavioral requirements and domain model, you really don't know what makes the most sense.

Certainly, though I am skeptical of that theory being true in the author's actual case. Because if it was, I would think the plurality in the URI would be consistent, and instead of

POST /accounts/4402278/close

You would have something like

POST /accounts/4402278/closures

Indeed—I would tend to argue that in most cases updating the value of an attribute on a resource for a complex operation is itself an antipattern.