My thinking behind #3-type-things is that you might want to be able to do both of these: GET .../order -> all orders GET .../order?t=org.openmrs.DrugOrder -> all drug orders
-Darius On Thu, Apr 19, 2012 at 8: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 > _________________________________________ 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]

