2

I'm designing REST API for devices management system.

Endpoints:

http://api.example.com/users
http://api.example.com/devices

I want to achieve that there is an endpoint that will do some action on selected device. Something like that:

http://api.example.com/devices/1/send_signal 

I know that is not REST compatible and I'm looking for suggestions to make it the right way.

I was thinking about adding another endpoint like:

http://api.example.com/calls

So when user send POST request with let's say deviceId parameter to that endpoint there will be new entry into the database (to have history of all calls and who called the function) and at the same time calls that function on specified device.

Would it be great architecture and REST compatible?

pisk1
  • 135
  • 7

3 Answers3

2
http://api.example.com/devices/1/send_signal

I know that is not REST compatible and I'm looking for suggestions to make it the right way.

It is REST compatible. REST doesn't care what spellings you use for your resource identifiers.

Would it be great architecture and REST compatible?

If this is what you want, think about how you would achieve the same result with a website. The client would open a bookmark in a browser, maybe follow some links, fill in a form, and submit it. That would all work because the (generic) browser understands the processing rules for HTML, and how to manage cache meta data in HTTP, and so on. There's no point in the chain where the client needs to compose an identifier -- it either uses one provided by the server as is, or it calculates one using the generic processing rules for HTML forms.

OP clearly uses a verb, to communicate intent and procedures, which is not RESTful.

No; this is a common misunderstanding. There's nothing in the REST architectural style that says anything about human readable semantics in identifiers. URL shorteners work.

It's analogous to saying that a variable name in a program should never be a verb, because that doesn't correctly communicate intent -- the compiler/interpreter doesn't care.

The use of spelling conventions does not make a URI more or less RESTful. See Tilkov. It might even be preferable to avoid using predictable identifiers, as that ensures that consumers read the identifiers provided in the hypermedia representations, which is the point.

VoiceOfUnreason
  • 40,245
  • 4
  • 34
  • 73
  • 1
    "REST doesn't care what spellings you use for your resource identifiers." True. However, a `send_signal` is not a misspelled resource, it is a procedure, an action, a verb. A `Signal` is a resource, a `sent_signal` (notice the T) or even a `Sgnlz`, whatever. But here, OP clearly uses a verb, to communicate intent and procedures, which is *not* RESTful. – berkes Dec 20 '18 at 11:10
  • @berkes I also agree with VoiceOfUnreason here, as already pointed out in my comments on your answer. A German wording states that between no knwoledge and partial knowledge the latter one is the more evil one. This, unfortunately, holds true in terms of REST as there are a lot of "recommendations" and "business best practices" that just portrait and advocate a wrong picture of REST, like the avoidance of verbs in URIs, and pragmatic people seem to follow and spread these guidelines blindly without rethinking the effects of their doing. – Roman Vottner Dec 20 '18 at 13:21
  • The relevant part of Tilkov's talk starts at [17:20](https://youtu.be/pspy1H6A3FM?t=1040). Interestingly, In [this SO answer](https://stackoverflow.com/a/2002092/3002584) he does mention that "including the verb in the URI is a design smell". For future readers, [this SO question](https://stackoverflow.com/q/1164154/3002584) and [this blog post](http://web.archive.org/web/20201220165204/https://twobithistory.org/2020/06/28/rest.html) about Fielding's Misappropriated REST Dissertation are related. – OfirD Jan 10 '21 at 22:18
1

You are right about your hunch. It is not proper REST. Sometimes that is OK, but most often, it is a sign that something in your Domain needs redesigning.

Quite often, there is a domain model waiting to be discovered. Most often, things like "send_signal" are telling you that you've modeled your API too close to some library, backend service or database. An API, after all, is the interface you provide.

AS I've written before: The R in REST stands for resource (which isn't true.... etc).

Think in resources. Not in procedures or calls, or internal tools, backend services or architecture of your system. That is your stuff. The API-user should only be bothered with (clean) abstractions that make senses to the API-user.

Both /call and /.../send_signal bother too much about procedures and internals.

What do you want to do with a device? You want to turn it's camera on? That would be an update to the Camera model on the Device with ID 1337:

PUT /device/1337/camera { power: "on" }

You want a device to bzip up some log files and send them to a debug-server? You're creating a DebugSession model:

POST /device/1337/debug_session { delivery_bucket: 42, compress: "bzip" }

You want a device to send a message to some server? Create a Message on a Device:

POST /device/1337/messages { to: john, body: "Hello World" }

And so on.

That is REST. In REST you model your domain models carefully. Lots of REST servers are really poor because they are very thin wrappers around some relational databases, and suffer from far too much leaky abstractions. Lots of other REST servers are really poor because they are written far too close around backend services, jobs being ran, or other internal details.

If I want to start a new server, I want to say:

POST /server/ { region: eu-1, size: xl, disk: 1MB }

And not:

POST /resources/blockdisks/create { size: 10GB } => 1337 is created
GET /resources/blockdisks/1337?include_attrs=mountpoint,format
GET /servers/available/map_for/eu-1?xl => DB-Zfaa-dd-12
POST /servers/reserve { id: DB-Zfaa-dd-12, attach: { id: 1337, mountpoint: /dev/sdb2, format: zfs }

(I'm not making this up, I had to deal with such API's they are a PIAS to use, and quite certainly an even bigger PIAS to maintain)

The lesson here: the first exposes a domain model of a Server, with few attributes only interesting to the user of the API. The second is modeled far too close around all sorts of internal tooling, and systems.

Edit: and all this completely ignores the even more important REST-part: discovery. Links, headers, redirects, etc. But you were explicitly asking about naming resources, so that's what my answer is about. Once you have your resources, your domain models, architectured, go back to the whiteboard and do it all over: now including Links, headers, or other metadata so that your API-clients can discover what they can do and where they can do that.

berkes
  • 25,081
  • 21
  • 107
  • 188
  • 1
    [1/4] While I totally agree that REST is about resources and the interaction model between client and server, it is also an architecture where the server "serves" the needs of a client by providing all of the information a client might need to proceed with its task. Similar to HTML, where the server provides a form where data can be put into and sent to the server, a REST API should send a form representation to the client (depending on which variant the client understands) as well if further input or configuration is needed. No out-of-band information is needed here. – Roman Vottner Dec 19 '18 at 16:25
  • 1
    [2/4] Next, the actual characters of a URI don't matter as a client should never interpret a URI but instead use some accompanying (meaningful) link relation name, which are either [standardized](https://www.iana.org/assignments/link-relations/link-relations.xhtml) or deduced from other means like domain or common knowledge like [schema.org](https://schema.org/). This allows server to change its URI structure anytime it has to without negatively impacting clients that respect link-relation names. – Roman Vottner Dec 19 '18 at 16:25
  • 1
    [3/4] Instead of using [typed resources](http://soabits.blogspot.com/2012/04/restful-resources-are-not-typed.html) meaningful to a client, client and server should use content-negotiation on well-defined media-types instead. Changing some fields later on might break clients that expect the availability or value of certain fields. Content-negotiation just allows clients and servers to communicate via well-defined representations both understand and therefore reduce interoperability issues. – Roman Vottner Dec 19 '18 at 16:26
  • [4/4] The final goal of applying a REST architecture is actually to decouple clients from servers, which make the former ones robust to changes while giving the latter one freedom to evolve. All of the above mentioned things, and a couple more, are necessary in order for an [architecture "deserving" to be called REST architecture](https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven) – Roman Vottner Dec 19 '18 at 16:26
  • @RomanVottner I deliberately kept the importance of content-discovery (links) and -negotiation out the answer. This is a very important part of REST, probably the most important. And also the most often ignored one. I agree. But it is out of scope for this question, which, to me, is about "what resources to communicate with". – berkes Dec 20 '18 at 11:08
0

I think you are on the right track. Based on what you said about the system, I would probably start with this way of doing it and go from there.

POST http://api.example.com/devices/123/calls

This would send the details of the call to the API and it would intern save the call to a data store and send off an event to the appropriate subsystem or internal library to call out to the device.

Then you could have the following endpoints to get call details.

GET http://api.example.com/devices/123/calls/456 
GET http://api.example.com/devices/123/calls -This would also include query parameters to limit the results in some way, probably by date.

If you want to get calls from all devices then you could to this with some query parameters restricting the result set, again maybe by date.

GET http://api.example.com/devices/calls 

Just as a side note, if this is an internal API used only by your applications RPC style may be appropriate. But, by following HTTP/REST you will make your software more malleable so you can use it in more ways without making it specific to any one function.

This is a good article on REST vs RPC if you'd like to learn more. https://cloud.google.com/blog/products/application-development/rest-vs-rpc-what-problems-are-you-trying-to-solve-with-your-apis

Dan H
  • 1,750
  • 2
  • 21
  • 35