GSoC 2018-HTML Form Entry Module and REST

Good point @madushan@owais.hussain in this case are you thinking that “getHtmlFormPage” would be more a call to allow someone to load and edit the schema of an Html Form vs actually something for end user rendering?

Take care, Mark

1 Like

@mogoodrich @owais.hussain Thank you! yes, the current HTML Form entry module generates the html out of HTML Form to be displayed and sends it to the client when a client wants to view. How can that be implemented in REST API, or it is not needed ?

since we are aiming to REST-ify the whole module, i believe it would be in the best of interests to create REST endpoints for all the functionalities.

1 Like

@piyush9620 Thanks! Has now the idea been changed from extending the current HTML form entry module to creating a separate HTMLl form entry rest module? Please correct me if I am wrong.

extending the HTML form entry module itself meant extending it in a separate REST module though the language may seem a little contradicting from the above conversation. The idea remains the same as of now, that we need to create a separate rest module until future discussions or inputs from other developers.

1 Like

@piyush9620 Thanks! How is creating a REST module different from creating a normal Openmrs module? Does the folder structure change a lot apart from the functionality?

https://wiki.openmrs.org/display/docs/REST+Module @madushan, here is some resource to help.

1 Like

@piyush9620 Thanks, This link talks about creating a normal module in oOpenmrs, so that’s what I should be creating in this scenario and extend it to support REST.

The “htmlformentryrest” module will really just be a normal OpenMRS module… whether it is added to the Html Form Entry module or put in a new module is really just a matter of where the code lives… the project should be the same regardless. It’s also possible that long-term we’d migrate all the new code in “htmlformentryrest” into “htmlformentry”. This just gives us a separate “sandbox” to work in.

@owais.hussain is your thought that an client-based application could request the complete HTML generated by a the HTML Form Entry module and then render it, sort of like an AngularJS template? (I haven’t thought this through entirely, but if we can get that to work, it would certainly be cool).

Take care, Mark

1 Like

@mogoodrich, even if we are able to send back the HTML for the form, the rendering has to be taken care by the client, right? On our part providing the HTML form as an xml shouldn’t be an issue.

2 Likes

There would be two cases… one case that would just return the XML that defines the form (this could be used by a client-side admin interface that would allow an administrator to modify the form) and another case that would actually generate the HTML of the form (could be used by a client-side tool that would actually render the form).

The second situation is the more important use case, because it would allow loading up HTML Forms inline without a full page reload. It might be worth starting with a spike to determine if there are any major blockers with making this work.

There’s actually already a sort-of an existing example of the second situation in the “HtmlFormEntryUI” module… check out the getAsHtml() method in “ViewEncounterWithHtmlFormFragmentController”. This allows you to request the HTML for the “view” mode of an Html Form RESTful as a UI Framework Fragment… we’d want to build something similar that used a standard RESTful interface instead of the UI Framework. And then we’d want to see if we could extend this to also return the HTML for the “edit” and “enter” versions of a form.

Hope that helps!

Take care, Mark

1 Like

@piyush9620 that’s exactly what I was thinking, the rendering burden should be on the client’s machine.

@mogoodrich I’ve just started learning AngularJS, but yes. The OWA should have a template to render the HTML form. And you’ve added another good point that the form can be partially rendered by the client, which gives flexibility. If we go with this approach, then it will be a bit challenging to complete the OWA in given time, but even if the approved student does just the Provider-Encounter-Obs, it should be considered as proof of concept I think.

I haven’t checked the HtmlFormEntryUI module. Will spend some time this weekend.

3 Likes

@owais.hussain, i see this thread sums up to these 3 requirements. (plz note the REST conventions will be taken care later)

endpoints type 1 : (GET/POST) deals with raw xml which defines the form (people will be able to manage forms via REST)

endpoints type 2 : (GET) deals with html generated from the raw form (in case someone wants to render the forms on their own)

endpoints type 3 : (GET/POST) deals with data filled in the forms(encounters and observations) in json format(instead of the regular form submission).

Is there anything you would like to add, @mogoodrich, @owais.hussain ?

2 Likes

@piyush9620 for the part 1 of the objective, I think this is it. The structure and scope of OWA is yet to be determined.

1 Like

This makes sense to me at a high level! Thanks @piyush9620!

Take care, Mark

@owais.hussain, we haven’t discussed much about the POC which is the second requirement for the project. Are we planning to include this POC as a separate plugable module? i have seen a page Login. This does pretty much what we need. Apart from that POSTMAN could alternately serve the purpose. Can u plz explain why we are particulary keen on building our own POC? Wouldn’t that be redundant? I think we can also use swagger to document as well as test the REST endpoints.

Thanks.

@piyush9620 I guess the goal is to extend the POC towards an OWA later.

1 Like

For authentication, and #2 above, I assume this is so this would work in a OWA outside of the OpenMRS UI? I haven’t worked with OWAs yet, but is there a standard pattern we use for authenication in these cases, or do we need to come up with something new?

@mogoodrich, what I have commonly observed is people provide user specific access keys to access the endpoints. E.g. google api console. Since that would be an entirely different project, passing the username and pass should do the trick for now.

@piyush9620 @madushan sorry I couldn’t do a call to explain what I did in the module I worked on but let me try to explain what I did here. A sample form I built is Smear Result form to capture results of a Smear Result test

To post to this form, my JSON data has information for the encounter(encounter date, location and provider) and concept id for the other fields. So my sample JSON looks like

{
    "encounterDate":  "Encounter date goes here",
    "encounterLocation": "Encounter location UUID",
    "encounterProvider": "Encounter Proivder UUID",
    "patient": "Patient UUID",
    "sampleId": "sample ID goes here",
    "sampleType":"concept ID for selected sample type",
    "appearance":"concept id for selected appearance",
    "result":"concept id for selected result"
}

Now let me explain the JSON

The first 4 fields are straight forward. I used those to create an encounter

final Encounter encounter = new Encounter();
encounter.setPatient(smearResult.getPatient());
encounter.setEncounterDatetime(smearResult.getEncounterDate());
encounter.setProvider(config.getEncounterRoleForForms(), smearResult.getEncounterProvider());
encounter.setEncounterType(config.getEncounterTypeForForms());
encounter.setLocation(smearResult.getEncounterLocation());
encounter.setCreator(Context.getAuthenticatedUser());
encounter.setDateCreated(new Date());
encounter.setForm(config.getSmearResultForm());
final Encounter saved = Context.getEncounterService().saveEncounter(encounter);
smearResult.setEncounter(saved);

Now for the other fields I save them as obs and attach them to the newly created encounter.

If you have played with the HFE, you’ll remember that to add a field like the Sample ID or Sample Type field, you write something like

<obs conceptId="232"/>

Now my implementation of the Specimen details section depends on what type the concept with ID 232 is.

If 232 is a text concept, it will normally just display a text box. For example Sample ID as shown above is a text concept.

An observation needs to be attached to an encounter and a concept. In this case concept 232. So what I did was, I set a global property SmearResultSampleConcept whose value is 232(ID of an actual concept in the sytem). So when saving my obs, I got an instance of this concept using it’s ID specified inside a global property as shown in line 74 of the code above. Then since this a text concept, I set the value for the obs which is what the user entered in the text field. Line 80 set’s the value of the obs by calling

Obs.setValueText(String)

Now we have an obs, attached to an encounter, a concept and it’s value specified to what the user entered on the frontend or what was sent in the JSON.

If concept 232 is a date or numeric concept, the idea is pretty much the same. But instead of setting the value as done for a text concept, I’ll set the value using

Obs.setValueDate(Date) 

or

Obs.setValueNumeric(Integer)

respectively.

Now if the concept is a complex concept, that is, it’s values are also concepts. Then the field will normally display a drop down. For example Sample Type is backed by a complex concept so the options in the dropdown will be answers already configured for this concept. So what I’m expecting in the JSON as value for Sample Type is actually the ID of a concept which is an acceptable answer for the concept backed by Sample Type concept. And I retrieve this concept answer using ConceptService.getConcept(Integer) and set it as value for the observation for the sample type using Obs.setValueCoded(Concept). See code below

Note SmearResult object is just a pojo with getters and setters for each field that will be present in the JSON.

2 Likes