[jboss-as7-dev] Detyped and REST configuration API
Brian Stansberry
brian.stansberry at redhat.com
Tue Nov 30 12:37:22 EST 2010
On 11/30/10 10:05 AM, David M. Lloyd wrote:
> On 11/30/2010 12:03 AM, Brian Stansberry wrote:
>> On 11/29/10 10:18 PM, David M. Lloyd wrote:
>>> On 11/29/2010 05:15 PM, Brian Stansberry wrote:
>>>> Updates via differencing:
>>>>
>>>> A model update consists of a client sending a detyped representation of
>>>> a part of the model. The update will include all of that portion of the
>>>> model; both modified and unmodified properties. The server compares that
>>>> detyped representation to the current state of the model and generates
>>>> the AbstractModelUpdate objects needed to bring the model up to the
>>>> desired state.
>>>
>>> I don't know if I agree with this approach. This means that to do an
>>> update you have to do a read-modify-write, so there's a race condition.
>>
>> In most cases there's inherently a race condition. The user has some
>> idea of the state of the system which may be outdated, and then tries to
>> perform an update. In a REST system this is handled with ETag headers
>> and IF-Match headers.
>
> Good point; however what I'm saying is if your update targets just one
> field on an element, then you can be guaranteed that you aren't going to
> reset some other field to an old value,
Gotcha. Yeah, part of the thinking behind the whole "id-only" element
was to reduce the scope for that kind of problem, but you're right, it
exists whenever there are multiple attributes for an element.
so the problem just disappears
> (at least, on the assumption that the user doesn't care what the old
> value was, that just want to change it to some new value; we could take
> it to an extreme and have a CAS type update but... meh).
>
>>> In addition, there are many update types which require simultaneous
>>> updating of fields which means that there is a larger class of invalid
>>> inputs which would need specialized error messages such as "if you
>>> update field blah, you also have to update field bzzt" and so forth.
>>
>> How is that avoidable with a detyped API? On the client side you have no
>> update class to enforce preconditions.
>
> My point being that if we use dedicated update objects (as opposed to
> generic model updates), we can perform more "regular" validation on the
> update object itself (i.e. these fields are required, these are
> optional) which means no specialized error messages, just generic
> "missing required field foo" kinds of things.
>
>>> I'll grant that many of our updates are adds and removes. But sometimes
>>> the address would be unknown until the add is complete (deployments for
>>> example); I think this general scenario (system-generated addresses) is
>>> perfectly valid.
>>>
>>
>> That's a typical REST scenario; you add a new child to a parent resource
>> and you get back the URL of that child, which tells you its id. That
>> doesn't seem like a hard thing.
>
> True.
>
>>> And don't forget that some of our updates will be related to a model
>>> element but won't actually *update* that model element. For example,
>>> "interrupt thread #5 from the pool defined by
>>> domain/subsystem/threads/pools/fred". Or it might even be something
>>> like "interrupt thread #1234 via domain/subsystems/threads"; it might
>>> not relate to that specific an element. Perhaps the updates themselves
>>> should be the combination of an update identifier with the address of
>>> any thing(s) being modified in the payload of the update itself.
> >
>> Good; the topic of this thread was "configuration API" but bringing in
>> discussion of non-configuration management operations is a good thing.
>> Management operations always seemed more RPC-ish and less RESTful.
>>
>> In general, my concern about the approach you're outlining is it feels
>> RPCish and not RESTful. I'm actually more comfortable with RPC, but we
>> have a requirement to provide a REST interface and I'm concerned about
>> straying so far from REST principles that the REST interface becomes an
>> unmaintainable hack.
>
> I'm not worried about that. We can support GET for reading (of course),
> PUT for adding (in SOME cases), LIST for certain read tasks, DELETE for
> removal (in SOME cases), and POST for nontrivial updates. It's
> REST-enough for me.
>
What's with the big scary capital "SOME cases"? Why not a big scary
capital "MOST cases"? (IOW what am I missing here?)
The POST for the non-trivial updates is going to end up being pretty
non-RESTy; it won't just be posting back the element fields, it will
need to include a parameter that identifies the update type.
I'm no REST purist; that's probably OK. I wouldn't mind having a REST
purist argue with us a bit about this though.
>>> Another prime example would be deployment. A deployment plan contains
>>> model information (i.e. the deployment name and content) as well as
>>> non-model information (i.e. the plan itself). It wouldn't be good to
>>> try to cram this into a pseudo-update of some sort of virtual fields or
>>> something.
>>
>> I see a deployment plan (or any updates that want deployment-plan-like
>> behavior) as being a resource that gets created, manipulated and then
>> can be referred back to (e.g. to obtain results).
>
> In the REST API, sure. However I think that this should be encapsulated
> in a single object in the untyped API - the REST server can take care of
> maintaining the state necessary to assemble the plan.
>
> In this way, an address is NOT constrained to just the single model.
> Which is true anyway - an address has to not only represent a position
> in the domain model, but also in the host models within the domain, and
> the server models within the hosts. It stands to reason that the REST
> API should also be able to access other, intermediate structures as well.
>
Absolutely.
>>> In other words I might ask for all deployments in server group X, and
>>> I'd get back a list of fully addressed model elements. Or I might ask
>>> for a specific configuration of a connector in a profile and get back
>>> just that connector, but fully addressed - it wouldn't be rooted in the
>>> domain.
>>
>> Or you might ask for all the subsystems in a profile, but not want the
>> full details; just their "ids". Granted, that could be handled as a
>> separate query, a sort of "getChildIds()" instead of "getChildren()".
>> For reads I saw an id-only element as a placeholder for children, not
>> for uninteresting parents. As you say, there is no need for
>> uninteresting parents; that's what the address is for.
>
> Well I think a REST-y "LIST" operation makes sense for this; return a
> list of addresses and there you go. In the API itself we could have a
> generic list operation which operates on mappy and listy things.
>
>> For writes, the complex update case I describe above can handled by
>> making the client provide multiple targetted updates (add extension, add
>> thread pool, add socket binding, add subsystem) wrapped in an atomic
>> update plan.
>
> That seems reasonable. That would just be a list of other updates I guess.
>
--
Brian Stansberry
Principal Software Engineer
JBoss by Red Hat
More information about the jboss-as7-dev
mailing list