GithubHelp home page GithubHelp logo

Actions vs. Properties about api HOT 15 CLOSED

webthingsio avatar webthingsio commented on August 19, 2024
Actions vs. Properties

from api.

Comments (15)

samgiles avatar samgiles commented on August 19, 2024

I'm not totally up on prior art yet, but having to make a distinction at this level just seems contradictory to the way the web as a platform works.

Having read the thread there, I still don't completely see why there needs to be a separate distinction and new terminology. HTTP verbs and response codes already seems perfectly suited to handle the wide variety of needs - if there are new needs, we should see how they fit into the broader picture of the HTTP protocol rather than come up with a schema definition to define stuff.

from api.

dpjanes avatar dpjanes commented on August 19, 2024

In IOTDB, we do not make a distinction, as in practice there's generally a deep coupling the "property" and the "action". For example, "action" of turning something on couples to the "property" of knowing whether it is on or off.

Thus we have attributes which can either be for actuation, for sensing, or for both, allowing us to use a common and semantic definition that covers both.

We believe that splitting attributes into "property" and "action" adds an unneeded level of complexity.

To change the state of a Thing, we PUT to the ostate of a Thing. To get the current state of a Thing, we GET from the istate of a Thing. istate and ostate are called bands, and this gives us a highly orthogonal model for dealing with a Thing's data: not just its state, but its metadata, its connectivity status, its model (a semantic description), and possibly other things.

A simple example of this would be the WeMo Socket, which you can see here. A transition from off to on will look like this:

INITIAL
{ istate: { on: false }, ostate: { on: null } }

PUT /istate { on: true } 
{ istate: { on: false }, ostate: { on: true } }

... note the light isn't on yet … this is the interstitial state
... time passes and a relay flips …

FINAL (note the ostate reset)
{ istate: { on: true }, ostate: { on: null } }

from api.

samgiles avatar samgiles commented on August 19, 2024

Hey 😄!

What do the istate and ostate represent (i.e. what's the difference between them semantically)? I'm not totally clear on that.

From first impressions it seems like you could do something equivalent relying on the semantics provided by HTTP

// RFC 2616 says PUT _should_ be idempotent.
PUT /light/0 `{ on: true }`
202 Accepted

// Time goes by
GET /light/0
200 OK `{ on: false }`

// Some more time goes by and the relay flips
GET /light/0
200 OK `{ on: true }`

from api.

dpjanes avatar dpjanes commented on August 19, 2024

The istate is the input state and the ostate is the output state. I originally thought the same as you and just had single state. This however, does not work because of the Interstitial period, that is, actuation takes time to complete.

This is a real - not hypothetical - state of the system and you'll note there's conflicting values if we just did GET /light/0.

{ istate: { on: false }, ostate: { on: true } }

The reason we're uncomfortable with concept initially is we're so used to software where things complete something close to instantaneously. This is not even close to being true in the IoT world, where things typically can take 100s of milliseconds if not seconds to complete.

Discovering that state had to be split was a happy moment, because then how to deal with all the other data associated with a Thing becomes apparent. In IOTDB parlance, we call each of these slices of data bands.

Thus:
GET /light/0
doesn't return anything except a pointer to URLs where to get data

GET /light/0/istate - the actual state of a Thing
GET /light/0/ostate - the state we want a Thing to transition to
GET /light/0/model - the semantic model for a Thing, e.g. the JSON-LD I linked to above
GET /light/0/meta - metadata
{
 "schema:name": "My fantastic Thing",
 ...
}
(and so forth)

I'll see if I can spin up an IOTDB instance on the web with HTTP and CoAP interfaces somewhere in the next day.

I've also got a bunch of slideshows on the subject, this may be a useful place to start as any
http://www.slideshare.net/dpjanes/semantic-metastandards-will-unlock-iot-interoperability

from api.

dpjanes avatar dpjanes commented on August 19, 2024

Note, if you want to change the name of a Thing

PATCH /light/0/meta
{
 "schema:name": "My ordinary Thing"
}

and so forth

from api.

benfrancis avatar benfrancis commented on August 19, 2024

@samgiles wrote:

Having read the thread there, I still don't completely see why there needs to be a separate distinction and new terminology. HTTP verbs and response codes already seems perfectly suited to handle the wide variety of needs - if there are new needs, we should see how they fit into the broader picture of the HTTP protocol rather than come up with a schema definition to define stuff.

This was my initial reaction too. But there are some use cases where this doesn't work very well.

From this article:

One example of such an operation is where you want to introduce a state change for a resource, but there are multiple ways in which the same final state can be achieved, and those ways actually differ in a significant but non-observable side-effect. Some may say such transitions are bad API design, but not having to model all state can greatly simplify an API. A great example of this is the difference between a “power off” and a “shutdown” of a virtual machine. Both will lead to a vm resource in the “DOWN” state. However, these operations are quite different.

From my comments on the W3C thread:

If we're being dogmatic about REST then there really shouldn't be any "actions" in a RESTful API because all resources should be nouns and the only verbs should be those defined by the HTTP protocol. However, it's a known problem that if followed rigidly this can sometimes result in a very complex API and there are cases where actions resources can actually make sense.

One recommendation is to to treat an /actions collection as a queue of actions to be executed so a new action can be POSTed into the queue. That is to say that you wouldn't call an action by a GET request on a resource with a verb in the name but rather you POST an action resource to add it to a queue of actions to be performed, where it is given a unique ID. You can then GET that resource by its ID (/actions/{id}) to find out its status, PUT a new version of the action to update it in the queue or DELETE it to remove it from the queue.

I wouldn't say that properties should therefore be read-only, but that actions can be used to define more complex behaviour which may modify multiple properties or modify state in different ways which may have different side effects.

In other words, properties should be set directly wherever possible (e.g. using a PUT request), but requesting an action to be added to a queue may be appropriate in certain more complex cases.

Another example I provided:

For example, a property may be set to turn a light on and off but an action might be used to tell it to fade out. The end result is the same (the property ends up in the off state) but the side effect is that the light gradually fades out in transitioning to this state. In this case calling an action would be preferable to setting a brightness property to 256 different brightness values in quick succession to achieve the same effect!

@samgiles Do you think there's a better way to model this in REST than POSTing action resources to an actions collection?

from api.

benfrancis avatar benfrancis commented on August 19, 2024

@dpjanes

we're so used to software where things complete something close to instantaneously

Not at all. Most of the JavaScript I write is asynchronous.

You can either wait for the state change to take effect before returning an HTTP response or respond with a 202 Accepted response which just means the request has been accepted for processing.

from api.

dpjanes avatar dpjanes commented on August 19, 2024

@benfrancis why does the code one writes being asynchronous matter? the interstitial state exists and is "interesting / important" to know.

  1. You push "turn on the light"
  2. Time passes - the command is being actuated, but is not complete
  3. The light turns on

You might not care about state 2 but it exists and lots of people do care about it. For example, the person turning on the light wondering "why isn't the light on?"

Now perhaps the argument is "well, that person will know because they issued the command and you've returned a Promise" (or whatever).

  1. how if someone else wants to know?
  2. the state actually exists, whether you expose it or not.

Or if the argument is "we're doing REST interfaces", points 1 & 2 still apply. And (as I posted on WoT list) REST isn't the starting point: what it is is the starting point.

Further reading on UX and Interstitial state on O'Reilly here

from api.

benfrancis avatar benfrancis commented on August 19, 2024

the interstitial state exists and is "interesting / important" to know.

Fair enough. You could represent that state with two booleans (as you have) or with an integer (0, 1, 2, 3) or a string "on", "of", "turningOn", "turningOff".

But this is all orthogonal to the question of properties vs. actions which I think is a separate issue.

from api.

dpjanes avatar dpjanes commented on August 19, 2024

You could represent it as 0, 1, 2, 3 (etc). but in practice you'll like represent it the same way as you invoked the action. Certainly that's the simplest way to do it, IMNHO.

This pattern appears over and over and over again in IoT devices (see github.com/dpjanes/homestar-*/models/* - I've gone through quite a few). What one calls actions and properties tend to be flip sides of a coin: "do X" and "what is X", where these are defined almost identically except for one refers to actuation and the other to sensing.

And thus back to the main point: you don't need properties vs actions any more than you need a HeadSideOfCoin and TailSideOfCoin models; you just need a single thing (which I call Attributes) which can express itself as as doing actuation or sensing or both.

from api.

samgiles avatar samgiles commented on August 19, 2024

This all makes sense from an end UX perspective. It's quite obvious to me that we need some way of querying the current state of some system. That makes sense. It also makes sense that we'd want to be able to query the desired state, whatever that might be: desired temperature of a room, desired on/off state of a light etc. I also like the fact that these are simply resources, to trigger some state change, we just PUT/PATCH the desired state.

I think the thing that confused me was the istate and ostate terminology.

from api.

benfrancis avatar benfrancis commented on August 19, 2024

@dpjanes wrote:

And thus back to the main point: you don't need properties vs actions any more than you need a HeadSideOfCoin and TailSideOfCoin models; you just need a single thing (which I call Attributes) which can express itself as as doing actuation or sensing or both.

Can you explain how you would represent the two actions examples given above using only your attributes model?

  1. Fading out a light over 3 seconds
  2. Rebooting a device

from api.

samgiles avatar samgiles commented on August 19, 2024

The thing that this doesn't capture is the "how" aspect of a desired state: "how to get from state A to B, fade in the light over a period of 20 seconds, and change the hue from #333 to #444 using a lerp over that period." But maybe this is an implementation detail, or we could borrow from CSS transitions to describe complex state transitions.

from api.

dpjanes avatar dpjanes commented on August 19, 2024

@samgiles exactly re: what I've been calling (for lack of a better word) "decorations", though I probably should come up with something better or precise.

Slight digression:
My primary interest / focus in the IoT is to create interoperability through semantics. So although we may be using keys like on, power, fade-in, fade-effect, transition-period, reboot or whatever in what we PUT/GET to/from ostate and GET from istate, we really "know" that we're taking about the concepts <turn-on-or-off> <transition-between-current-state-and-new-state>, reboot and so forth. (And the way we represent these universal concepts is by URLs)

So back to the main point / question re: @benfrancis. Let's say we want to make an awesome "Netflix & Chill Effect" for our living room, where part of that involves the lights taking 3 seconds to fade out. Let's pretend that everyone understands { on: false } to mean "turn yourself off". Furthermore, let's assume that all fadeable lights understand { transition-period: 3 }. So we just write to all those lights:

PUT /light/34/ostate
{
 "on": false,
 "transition-period": 4.5
}

or possibly even better

PUT /light/34/ostate
{
 "brightness": 0,
 "transition-period": 4.5
}

For lights that don't understand "transition-period" (or more correctly, that semantic concept of a transition) we just do

PUT /light/19/ostate
{
 "on": false
}

Since everything has a model, the client actually sending these commands can choose to do the latter at the beginning of the 4.5 second period, the end or the middle, or whatever to taste.

Rebooting - or any other one-of event - is just like anything else

PUT /computer/0/ostate
{
  "reboot": (some value, I'm not going to get into it just right now)
}

Important digression: I'm not proposing the magic words "on", "transition-period", or "reboot" be standardized (I don't believe this is possible). They're just to illustrate this particular point.

from api.

mrstegeman avatar mrstegeman commented on August 19, 2024

@benfrancis This can be closed, I believe.

from api.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.