-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
revisiting decorators for actions/properties/etc. #237
Comments
This is something I explored at one point though can't now remember if/where I ever implemented it. I basically changed the class so that the methods were named after the WoT standard, e.g. something like
It'd be good to have an example of how this would look, but I think I understand and agree.
Agreed. We're verging into "framework" rather than library territory here but I think we've been heading that way for a while now anyway.
See my above point. I think this is the best way forward.
I'm having to remind myself to be honest... This all seems sensible though. |
I should add that a lot of the stuff you mentioned here is hanging over from before the WOT spec was standardised, and we were independently converging on more or less the same structure. We had some functionality that didn't map onto the draft spec, hence us defining everything in terms of HTTP methods still. I really do think that making the HTTP method-based views a kind of behind-the-scenes thing you can override if needed, and focusing on WoT affordance-based views makes much more sense at this stage. |
ok, that sounds really sensible. I have a MWE of an action decorator for extensions working in the autofocus extension: Generalising this so it's ready for LabThings probably involves:
That's enough work that it will take a while - and I might get some opinions on whether this verison of the autofocus plugin makes more sense before putting it in. |
I am sure we have discussed in the past the merits of defining a
View
subclass for each endpoint, e.g. in anExtension
. I have a nasty feeling that I probably argued strongly against using decorators because they often make life quite confusing. However, I'm coming round to the idea. My use case is this:I'm writing some code in an extension, which includes a function to do something. For argument's sake let's say that function should be an
Action
but I think the same consideration applies to properties. Ideally, I'd like it to be accessible either via HTTP or via Python. Currently, what I do is:There are several things that are less than ideal here:
I can see a few ways to make it better:
ActionView
classes are more or less always wrapping a function to do an action. This would, for example, mean that instead of writing apost
method, I would supply anaction
function. Doing that explicitly makes it way easier to wrap the action function nicely, e.g. propagate the docstrings.ActionView
right next to the function it's wrapping. This makes it harder to miss things being out of sync, and could also eliminate the need to register views explicitly.I think if I argued against custom decorators in the past, it was because I felt they were non-standard ways of doing things, and wouldn't make sense to someone familiar with Flask. That's true, but I think there's enough that's non-standard about e.g. the way we generate our APISpec that this battle is possibly lost anyway. Also, if we define a more "helpful"
ActionView
subclass, it potentially provides a point of familiarity for Flask developers - so if they understand how@action
maps ontoActionViewWrapper
(which is potentially quite simple), it's easier to figure out what happens once you have aView
.Also, I think when we made this decision, it was more likely that you would want control over the get/post/delete/whatever methods. Now that the WoT specification is finalised, it's pretty well defined what each HTTP method should do, and I'm in favour of providing a mapping from HTTP methods to meaningful WoT interactions. I.e. a
PropertyView
always reads a property withGET
and writes it withPUT
and may define a way to update it withPOST
. So probably we should, by default, define a getter, setter, and update method - not all of which must exist. Similarly, anActionView
will always run actions withPOST
and return status withGET
, so it makes sense to simply have a function responsible for running the action (which is what's currently implemented inActionView.post
. This also means that overridingActionView.post
would allow an action to do something custom before it's spawned in a background thread, such as validating arguments and returning an HTTP error code if they're wrong.I'm raising this issue so @jtc42 can tell me why I was dead against this in the past, or if he remembers anything important that's not reflected in the discussion above.
The text was updated successfully, but these errors were encountered: