I just replied on the ticket...
@Roger, I really really don't like the idea of ignoring extra properties.
Trying to update a resource with a property it doesn't support should _not_
fail silently, it should give you a BAD REQUEST.
>From my proposal above, I think we _should_ include a discriminator
property when you're doing a POST to create, e.g:
{code}
{
type: "org.openmrs.module.lab.LabModuleOrder",
startDate: "2011-03-04",
labModuleSpecimen: "<uuid>"
}
...will be delegated to the registered handler for LabModuleOrder, rather
than being handled directly by OrderResource.
{code}
The one revision I'd make to what I said before is that we should hide the
fully-qualified classnames from the end-user of REST. The module should do
something like
{code}
registerSubclass(OrderResource.class, "LabModuleOrder", new
LabModuleOrderSubclassHandler());
{code}
-Darius
On Thu, Apr 19, 2012 at 10:15 AM, Friedman, Roger (CDC/CGH/DGHA) (CTR) <
[email protected]> wrote:
> That's why I'd like to see subclasses appear as "flat"; you'd still have
> to update up the tree, but you could use the same body and each layer would
> pick off the variables it needs. As for create, Hibernate would take care
> of the splitting and only the subclass would be exposed, so there's no need
> for multiple updates. But this means that there would be no errors for
> specifying "extra" variables.****
>
> ** **
>
> *From:* [email protected] [mailto:[email protected]] *On Behalf Of *Darius
> Jazayeri
> *Sent:* Thursday, April 19, 2012 1:01 PM
>
> *To:* [email protected]
> *Subject:* Re: [OPENMRS-DEV] REST WS and subclasses****
>
> ** **
>
> Burke, if we incorporate Jeff Wishnie's off-list suggestion to us about
> making the "Subclass links to Superclass" also include a link from the
> superclass to the subclass, we could do something like this:****
>
> ** **
>
> GET order ->****
>
> [****
>
> {****
>
> // order properties here****
>
> links: [****
>
> { rel: "self": uri: "order/<uuid>" },****
>
> { rel: "more-details": uri: "drugorder/<uuid>" }****
>
> ]****
>
> },****
>
> {****
>
> // order properties here****
>
> links: [****
>
> { rel: "self": uri: "order/<uuid2>" },****
>
> { rel: "more-details": uri: "laborder/<uuid2>" }****
>
> ]****
>
> }****
>
> ]****
>
> ** **
>
> GET drugorder ->****
>
> {****
>
> // only DrugOrder-specific properties here****
>
> order: { ref representation of the superclass },****
>
> links: [****
>
> { rel: "self": uri: "drugorder/<uuid>" }****
>
> ]****
>
> }****
>
> ** **
>
> Personally I prefer my originally-proposed approach #3 instead of this,
> though. It seems like it would be easier for clients to put all a DrugOrder
> properties (own and inherited) in a single document, rather than having
> dosage in one document and startDate and concept in a linked document. As I
> phrased it before, it makes sense to me that if subclasses "inherit the *
> meaning* of the superclass, not just its implementation details" then it
> makes sense to expose them all through a single resource...****
>
> ** **
>
> (But I'm no REST expert, so...)****
>
> ** **
>
> -Darius****
>
> ** **
>
> ** **
>
> On Thu, Apr 19, 2012 at 9:29 AM, Burke Mamlin <[email protected]>
> wrote:****
>
> Orders are often approached generically (e.g. getting a list of active
> orders; creating order sets that contain meds, tests, educational
> materials, referrals, etc.; etc.), all orders share a base of properties &
> workflows, and we want to allow for modules to add additional types. By
> treating all orders types as "orders", we allow consumers to treat
> different types differently when they know about them, but also fall back
> to treating them as generic orders for those types they don't understand.*
> ***
>
> ** **
>
> For example, if I want to generate a list of all active orders, I can go
> to one place, get this list, and show the names of them, who ordered them,
> etc. rather than fetching the active list from each resource (drugorder,
> laborder, radiologyorder, nursingorder, referralorder, dietorder,
> activityorder, precautionorder, and callorder) and then be forced to
> refactor my code when I want to include Roger's latest whirlygigorder.****
>
> ** **
>
> We could model all order types as separate resources, if we can still have
> a centralized mechanism for dealing with orders (e.g., fetching all active
> orders) and ensure that all of these resources have some shared part of
> their representation that was guaranteed to not only have the same
> properties, but follow the same business logic (e.g., all orders must have
> an orderer, the definition of "active" needs to be applied the same across
> all orders, etc.)****
>
> ** **
>
> -Burke****
>
> ** **
>
> On Thu, Apr 19, 2012 at 11:08 AM, Saptarshi Purkayastha <[email protected]>
> wrote:****
>
> The Approach#3 is extremely complex and means that someone needs to
> understand the type of "what"****
>
> ** **
>
> A client does not have to understand the types, just resources and so to
> me the approach #1 is generalizable and concise to understand as a general
> pattern when having to communicate with OpenMRS web services. Again why
> would it be a problem to use Approach#1 with drugorder or laborder
> resource??****
>
>
> ---
> Regards,
> Saptarshi PURKAYASTHA
>
> My Tech Blog: http://sunnytalkstech.blogspot.com
> You Live by CHOICE, Not by CHANCE****
>
>
>
> ****
>
> On 19 April 2012 06:43, Darius Jazayeri <[email protected]> wrote:**
> **
>
> Hi All,****
>
> ** **
>
> We had a very good design call discussion on this, and Burke and I got
> some brief, dense, and helpful insight on this from Jim Webber.****
>
> ** **
>
> The key insight: "Dealing with inheritance is easy: REST doesn't do it."
> Basically: think of REST resources as simply exchanging documents. There
> can be links between documents, but they are not allowed to have any formal
> type hierarchy.****
>
> ** **
>
> So, after wrapping our heads around that, we've come up with three
> different approaches to hide inheritance in the REST API, each applicable
> to different things in the underlying Java class model:****
>
> ** **
>
> *Approach #1 - Subclass links to Superclass*****
>
> *Used for: Person/Patient*****
>
> In the REST API, the subclass document contains only subclass-specific
> attributes, as well as a link to the superclass document. Example:****
>
> GET patient/1234 ->****
>
> {****
>
> identifiers: [ ... ],****
>
> person: { ref representation of person/1234 }****
>
> }****
>
> ** **
>
> Even though the underlying Patient object inherits from Person, the
> PatientResource should hide this. Thus you cannot edit a birthdate via the
> patient resource, *and* creating a patient requires two POSTs (one to
> create a person resource, the next to create a patient resource that links
> to the person resource).****
>
> ** **
>
> *Approach #2 - Hide the Superclass*****
>
> *Used for: ActiveListItem/Allergy/Problem*****
>
> We use this approach when the multiple subclasses are not meaningfully
> related to each other, and they only share a superclass for ease of
> implementation. The REST API has no resource for the superclass. Each
> subclass is its own resource, which contains the union of the properties of
> its superclass and itself.****
>
> ** **
>
> *Approach #3 - Single Resource for Class Hierarchy*****
>
> *Used for: Concept/ConceptNumeric/ConceptComplex*****
>
> *Used for: Order/DrugOrder/XyzModuleOrder*****
>
> We use this approach when multiple subclasses really are different
> versions of the same basic thing. In other words, they inherit the meaning
> of the superclass, not just its implementation details.****
>
> The REST API has a single resource (Concept, Order) that manages the
> documents for all subclasses. Each document represents an underlying
> instance of some class in the hierarchy, and it contains all properties of
> that class, including inherited ones.****
>
> For example, GET order?patient=1234 ->****
>
> [****
>
> {****
>
> type: "org.openmrs.DrugOrder",****
>
> startDate: "2011-01-01",****
>
> // other Order properties go here****
>
> dosage: "100mg",****
>
> // other DrugOrder properties go here****
>
> links: [ { rel: "self", uri: "order/11111" } ]****
>
> },****
>
> {****
>
> type: "org.openmrs.Order",****
>
> startDate: "2011-02-03",****
>
> // other Order properties go here****
>
> links: [ { rel: "self", uri: "order/22222" } ]****
>
> },****
>
> {****
>
> type: "org.openmrs.module.lab.LabModuleOrder",****
>
> startDate: "2011-03-04",****
>
> // other Order properties go here****
>
> specimen: { ref representation of a lab specimen },****
>
> // other LabModuleOrder properties go here****
>
> links: [ { rel: "self", uri: "order/33333" } ]****
>
> }****
>
> ]****
>
> ** **
>
> I've put a discriminator field in here ("type" might not be a safe name)
> because it seems quite useful, and I think it's necessary for object
> creation.****
>
> For example: POST order****
>
> {****
>
> type: "org.openmrs.module.lab.LabModuleOrder",****
>
> startDate: "2011-03-04" ****
>
> }****
>
> ...will be delegated to the registered handler for LabModuleOrder, rather
> than being handled directly by OrderResource.****
>
> ** **
>
> Implementation-wise:****
>
> - we are going to count on the underlying OpenMRS API (and ultimately
> Hibernate) to work such that if we do OrderService.getOrdersByPatient(1234)
> we get back a List<Order> whose individual items are actually of their
> correct subclasses.****
> - the core RESTWS module, and other modules, need to register handlers
> for their known subclasses****
> - we will have to write some code, but that's the fun part. :-)****
>
> Thoughts?****
>
> ** **
>
> -Darius****
>
> ** **
>
> ** **
>
> On Wed, Apr 18, 2012 at 6:35 AM, Burke Mamlin <[email protected]>
> wrote:****
>
> My biggest concern is that it requires that consumers of the API
> know/learn our data model; however, since the person is presented as a
> property of the patient and gender as a property of the person (not the
> patient directly), it's about as good a solution as I can imagine.****
>
> ** **
>
> -Burke****
>
> ** **
>
> On Tue, Apr 17, 2012 at 10:42 PM, Darius Jazayeri <[email protected]>
> wrote:****
>
> Yes, I meant what you said Burke.****
>
> (Hopefully that was my only typo.)****
>
> -Darius (by phone)****
>
> On Apr 17, 2012 6:48 PM, "Burke Mamlin" <[email protected]> wrote:**
> **
>
> Darius,****
>
> ** **
>
> Did you mean to two posts, one to patient & the other to person? Both of
> yours were to the same resource.****
>
> ** **
>
> This implies that if you want to modify a patient's gender *and* identifiers,
> you have to do *two* POSTs.
> For example:
> POST patient/abcd1234 { identifiers: [ ... ] }
> POST *person*/abcd1234 { gender: 'M' }****
>
> ** **
>
> Cheers,****
>
> ** **
>
> -Burke****
>
> ** **
>
> On Tue, Apr 17, 2012 at 8:01 PM, Darius Jazayeri <[email protected]>
> wrote:****
>
> Hi All,****
>
> ** **
>
> On tomorrow's design call one topic we will discuss is how to properly
> represent inheritance and subclasses in a RESTful way. Fun and exciting
> background discussion can be found on the ticket:
> https://tickets.openmrs.org/browse/RESTWS-221. Call-in details are
> here<https://tickets.openmrs.org/browse/RESTWS-221>
> .****
>
> ** **
>
> My proposal, generally supported by Saptarshi, and disliked by Roger, is
> that we represent a subclass as basically the composition of a superclass
> resource, and a subclass resource contains subclass-specific properties,
> and a pointer to the superclass.****
>
> ** **
>
> For example: GET patient/abcd1234 ->****
>
> {****
>
> identifiers: [ ... ], // this is the only Patient-specific property***
> *
>
> links: [****
>
> { rel: "self", uri: "patient/abcd1234" }****
>
> ],****
>
> person: { // this is a pointer to the superclass****
>
> names: [ ... ],****
>
> gender: 'M',****
>
> // other properties on the Person superclass follow ****
>
> links: [****
>
> { rel: "self", uri: "person/abcd1234" }****
>
> ]****
>
> }****
>
> }****
>
> ** **
>
> This implies that if you want to modify a patient's gender * and* identifiers,
> you have to do *two* POSTs.****
>
> For example:****
>
> POST patient/abcd1234 { identifiers: [ ... ] }****
>
> POST patient/abcd1234 { gender: 'M' }****
>
> ** **
>
> You should be able to *create* a patient in a single POST, but not update
> one that way.****
>
> ** **
>
> At first this seems inconvenient, and unintuitive for someone who's used
> to the OpenMRS Java API. The reason for this is that I think it's necessary
> to support web-standard caching, which allows web service scalability.
> Basically, imagine that someone may be running a reverse-proxy on their
> server, which caches resources generated by the server and serves them up
> to many web clients, relieving server load. In order for that reverse-proxy
> cache to avoid serving up stale data, we cannot allow doing POST
> patient/abc123 to modify the resource at person/abc123. (According to web
> standards, if the cache sees a POST to patient/abc123, this invalidates
> that specific cache entry, but all of this is invisible to the
> server.) Thus my proposal.****
>
> ** **
>
> I'm only moderately certain I'm approaching this right, so if you know or
> suspect the right answer to this problem (especially if it's different from
> my proposal), please reply and/or join us on the design call tomorrow!****
>
> ** **
>
> -Darius****
>
> ** **
>
> PS- The other topic we'll discuss on the call is Wyclif's proposal for a
> module, that will allow us to reboot our implementation of orders and order
> entry, such that we implement something better, and it runs on both old and
> new versions of OpenMRS. All in all this will be an action-packed call.***
> *
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
>
> ** **
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
>
> ** **
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
>
> ** **
>
> ** **
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
>
> ** **
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
>
> ** **
> ------------------------------
>
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
> ****
> ------------------------------
> Click here to
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
> OpenMRS Developers' mailing list
>
_________________________________________
To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to
[email protected] with "SIGNOFF openmrs-devel-l" in the body (not
the subject) of your e-mail.
[mailto:[email protected]?body=SIGNOFF%20openmrs-devel-l]