Can we remove "subclass" from any of this? That term is not intuitive and has no clinical meaning – e.g., instead use something like registerOrderTypeor registerOrderClass, depending on how we decide to decide to model different types of orders. If we follow the path laid out during the design call and start out just supporting different types as orderables using concept classes, then I'd favor registerOrderClass or registerOrderableClass.
-Burke On Thu, Apr 19, 2012 at 1:29 PM, Darius Jazayeri <[email protected]>wrote: > 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 >> > > ------------------------------ > 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]

