I just ran into a handy little utility: jsonpretty.
$sudo gem install json jsonpretty
While
$curl -i http://localhost:8081/openmrs-standalone/ws/rest/v1/catalog
gives you something like this:
{"catalog":[{"name":"Cohort","operations":[{"name":"GET http://localhost:8081/openmrs/ws/rest/v1/cohort?q","description":"Fetch all non-retired that match this parameter"},{"name":"GET http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}","description":"Fetch by unique uuid"},{"name":"GET http://localhost:8081/openmrs/ws/rest/v1/cohort","description":"Fetch all non-retired"},{"name":"POST http://localhost:8081/openmrs/ws/rest/v1/cohort","description":"Create with properties in request"},{"name":"POST http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}","description":"Edit with given uuid, only modifying properties in request"},{"name":"DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}?!purge","description":"Delete this object from the database"},{"name":"DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}?purge","description":"Delete this object from the database"}],"url":"http://localhost:8081/openmrs/ws/rest/v1/cohort","representations":[{"name":"ref","properties":["uuid","display","links"]},{"name":"default","properties":["uuid","name","description","voided","memberIds","links"]},{"name":"full","properties":["uuid","name","description","memberIds","voided","auditInfo","links"]}]},{"name":"CohortMember","operations":[{"name":"GET http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members/{uuid}","description":"Fetch by unique uuid"},{"name":"GET http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members","description":"Fetch all non-retired"},{"name":"POST http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members","description":"Create with properties in request"},{"name":"POST http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members/{uuid}","description":"Edit with given uuid, only modifying properties in request"},{"name":"DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members/{uuid}?!purge","description":"Delete this object from the database"},{"name":"DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{parentUuid}/members/{uuid}?purge","description":"Delete this object from the database"}],...
adding jsonpretty:
$curl -i http://localhost:8081/openmrs-standalone/ws/rest/v1/catalog | jsonpretty
gets you something much prettier:
{
"catalog": [
{
"name": "Cohort",
"operations": [
{
"name": "GET http://localhost:8081/openmrs/ws/rest/v1/cohort?q",
"description": "Fetch all non-retired that match this parameter"
},
{
"name": "GET http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}",
"description": "Fetch by unique uuid"
},
{
"name": "GET http://localhost:8081/openmrs/ws/rest/v1/cohort",
"description": "Fetch all non-retired"
},
{
"name": "POST http://localhost:8081/openmrs/ws/rest/v1/cohort",
"description": "Create with properties in request"
},
{
"name": "POST http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}",
"description": "Edit with given uuid, only modifying properties in request"
},
{
"name": "DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}?!purge",
"description": "Delete this object from the database"
},
{
"name": "DELETE http://localhost:8081/openmrs/ws/rest/v1/cohort/{uuid}?purge",
"description": "Delete this object from the database"
}
],
"url": "http://localhost:8081/openmrs/ws/rest/v1/cohort",
"representations": [
{
"name": "ref",
"properties": [
"uuid",
"display",
"links"
]
},
{
"name": "default",
"properties": [
"uuid",
"name",
"description",
"voided",
"memberIds",
"links"
]
},
{
"name": "full",
"properties": [
"uuid",
"name",
"description",
"memberIds",
"voided",
"auditInfo",
"links"
]
}
]
},
...
Nice! Thank you jsonpretty! 🙂
I wanted to list out some observations for a patient and used the following Groovy script:
def sql(s) {admin.executeSQL(s,true) }
patientIdentifier = "999-3" // a test patient, of course
sql("""
select
date(o.obs_datetime),
(select name from concept_name where concept_id=o.concept_id limit 1) as question,
case c.datatype_id
when 1 /* numeric */ then cast(o.value_numeric as char)
when 2 /* coded */ then (select min(name) from concept_name where concept_id=o.value_coded)
when 3 /* text */ then value_text
when 6 /* date */ then cast(date(o.value_datetime) as char)
when 7 /* time */ then cast(time(o.value_datetime) as char)
when 8 /* datetime */ then cast(o.value_datetime as char)
when 10 /* boolean */ then if(o.value_numeric=1,'TRUE','FALSE')
else '?'
end as answer
from
obs o
left outer join
concept c
on c.concept_id=o.concept_id
where
o.person_id = (select patient_id from patient_identifier where identifier = '$patientIdentifier' limit 1)
order by
o.obs_datetime desc
""").collect{ it.join(": ") }.join("n")
which generated output like this:
2011-02-18: PATIENT HAD SEX IN LAST 6MO: TRUE 2011-02-18: PlAN FOR METHOD OF FAMILY PLANNING, DETAILED: ? 2011-02-18: QUANTITY: 5 2011-02-18: FAMILY PLANNING METHOD PLAN: INITIATION 2011-02-18: METHOD OF FAMILY PLANNING: ECPS 2011-02-18: HIV DISCLOSURE TO ANYONE, SPECIFIC: OTHER HOUSEHOLD MEMBER 2011-02-18: REASON FOR REFUSAL - FAMILY PLANNING: TRYING TO CONCEIVE NOW 2011-02-18: PlAN FOR METHOD OF FAMILY PLANNING, DETAILED: ? 2011-02-18: METHOD OF FAMILY PLANNING: MALE CONDOMS 2011-02-18: QUANTITY: 5 2011-02-18: FAMILY PLANNING METHOD PLAN: INITIATION 2011-02-18: METHOD OF FAMILY PLANNING: BTL 2011-02-18: FREETEXT, GENERAL: POSITIVE 2011-02-18: REASON FOR REFUSAL - FAMILY PLANNING: ABSTINENCE 2011-02-18: FAMILY PLANNING: TRUE 2011-02-18: REVIEW OF MEDICAL HISTORY: ICTERUS 2011-02-18: PATIENT REPORTED PROBLEM: YES 2011-02-18: CURRENT MEDICATIONS: ALUVIA 2011-02-18: REVIEW OF MEDICAL HISTORY: DEPRESSION
Here’s a simple jetty server using a short Groovy script:
@Grab(group='org.mortbay.jetty', module='jetty-embedded', version='6.1.14') import org.mortbay.jetty.* import org.mortbay.jetty.servlet.* import groovy.servlet.* import javax.servlet.* import javax.servlet.http.* class MyServlet extends HttpServlet { void doPost(HttpServletRequest request, HttpServletResponse response) { println "--- Received ${new Date()}n" + request.getParameter('data') } } def server = new Server(8888) def root = new Context(server, "/", Context.SESSIONS) root.setResourceBase(".") root.addServlet(new ServletHolder(new MyServlet()), "/") server.start()
Running the script with groovy AtlasServer.groovy will accept HTTP POSTs at the designated port (8888) and dump posted data to the screen. Â For example:
$ curl -X POST -d "data=Hello world!" http://localhost:8888/
should dump “Hello world!” to the screen. Â Press Ctrl+C to abort the server.
Here’s a shout out to our friends at ThoughtWorks. They had a code jam on the Flowsheet Module a few weeks ago and knocked out over half a dozen key tickets in a single day as well as making progress on others. The Flowsheet Module is being installed into OpenMRS at AMPATH in Kenya to allow both data managers and providers convenient access to their patients’ data and to help improve the efficiency and quality of care for the over 300,000 patients within the system… thanks to: Khaarthigha S, Rajiv RA, Pavithra K, Geetha B, Saravana K, Arvind Kumar C, Senthil V S, Prabha P, Shanum, Ponnulingam R, Alexal, Vinoth KR, Nithyan, Gobinath T, Balaji G, Ragavan G, and Chandru. You all rock! And it looks like you had some fun in the process. I especially enjoyed the image of two laptops per lap!
Just upgraded to Firefox 4 beta 7 on my MacBook Pro and the (three finger) swipe down gesture I had grown to love (thanks to Will Henderson’s MultiClutch), suddenly became a “show tab view” gesture. This is no good! I’ve already become accustomed to swiping down to close tabs in Firefox.
A little googling, and I was able to get back my swipe-down-to-close-tab gesture and move the show tab view gesture to SHIFT + swipe down:
Now that gestures are supported on Firefox, I no longer need MultiClutch settings for Firefox.
Own a MacBook Pro and an iPad? Â Tired of carrying around both? Â Meet the iPad Pro.
I’m looking forward to the day when the monitor of my MacBook Pro becomes an iPad. Â No extra things to carry around. Â If you want to run to a quick meeting or browse on the couch, just snap off your monitor and go (it’s an iPad). Â Miss your keyboard, DVD drive, extra ports, extra battery life, etc.? Â Just plug your iPad back onto the iPad Pro base and you’ve got a full laptop. Â Keep a cloth in your bag to wipe off those fingerprints and stop freaking out when people touch your monitor — it’s a multitouch monitor, after all.
Trying to figure out how we can improve the efficiency of our code reviews. Finding some interesting stuff on the web…
Like this article: Limit the checklist to 7±2 items. Automate the automate-able and let existing code review data drive the list of common mistakes.
Here is a list of articles, white-papers, and documentation around peer code review. Hmmm. Several resources, but not enough time to look at them all.
Some nice pointers here, but nothing game changing.
A good summary article here.
And here (and here) is an interesting take by Torvalds that Paul found.
Plan on talking with developers to brainstorm on it…
It appears that the folks at Shapiro’s Deli are almost as proud of Dad as I am…
At the IMeCA Meeting in Lima, Peru listening to Hamish present about OpenMRS in English with real-time Spanish translation … and Hamish is in Kigali, Rwanda! Now that is cool!