...
OpenMRS is an electronic medical record platform. Basically we provide an API and data model for storing and analyzing patient-level data, and a reference application that's used in 40+ mostly-developing countries. The system includes "core" code and pluggable "modules" that allow very powerful extensions of functionality, and UI-level customization.
...
OpenMRS Web Services
In the past, people have written several web service modules for OpenMRS, but they've never had enough high-level design or buy-in.
Now, for the first time, we're really dedicating our core development team to doing web services right. We need to build a module that exposes our API over web services, in a way that we will support going forwards, and with a design we're proud of.
Caveat: we have very little expertise with web services.
We did a first pass at designing a web service API that was going to be exposed via both REST and SOAP using Apache CXF. We talked to Ola Bini a month ago and he told us (nicely) that this was all wrong, and we needed to learn about REST, resources, and representations. So we bought a couple copies of REST in Practice, and completely re-did our design. We feel pretty happy with our new design, but we really need expert feedback to tell us whether or not we're on the right track, and what we should do differently. Hopefully this time the answer isn't "everything". :-)
Version 1 Requirements
We polled the broader OpenMRS community, and came up with a list of User Stories to include in Version 1 of the module. Very concisely they are:
...
The API we are going to expose in our 1.0 pass at web services is entirely about doing CRUD on a data store. We're not dealing with any application flow or business logic. As such we will aim for level 2 of the Richardson Maturity Model (described by Martin Fowler here) and ignore the idea of embedding state transitions in our resources. Is this a mistake?
We will allow Spring to automatically transform our results to json or xml depending on the HTTP request. ( This probably prevents us from having a proper DAP or XSD. Is this a mistake?)
We'll be following (mostly) standard practice with HTTP methods for domain object CRUD:
- Create: POST /ws/rest/patient
- Search: GET /ws/rest/patient?q=name+or+identifier
- Retrieve: GET /ws/rest/patient/uuid
- Update: POST /ws/rest/patient/uuid with the request content the properties we want to change on the object
- e.g. to change a patient's birthdate you'd POST { "birthdate": "1978-05-24" }
- does this seem okay, rather than using PUT with the complete object?
- Delete: DELETE /ws/rest/patient/uuid
- this actually means "mark deleted" in OpenMRS
- "Delete forever": DELETE /ws/rest/patient/uuid?purge=true
- actually deletes an entity from the database
- is there a better way to indicate this special, rarely-used method?
...
- A patient's program enrollment has a top-level URI /ws/rest/enrollment/uuid (i.e. it's not included within the patient)
- To see what programs a patient is enrolled in: GET /ws/rest/patient/patient-uuid/enrollments
- To see what patients are enrolled in a program: GET /ws/rest/program/program-uuid/patients
- To enroll a patient in a program you can do either of:
- POST /ws/rest/patient/patient-uuid/enrollments // may omit the patient from the request body
- POST /ws/rest/program/program-uuid/patients // may omit the program from the request body
- POST /ws/rest/enrollment // must specify both patient and program in the request body
Does this sound right?
Authentication
A client needs to be authenticated to be able to do anything. We plan to support having the client pass a username/password with every request, or (preferrably) to have the client authenticate by posting to an authentication resource and getting back a token representing a login session. The client would then pass that token in the header of future requests, until it expires.
We assume this will be straightforward once we sit down to design and implement it, and we should be worried about this. Any words of warning? Any examples we should look at or obvious technology terms to search for?
Some Java Code
We've tried to put together a framework that will make it very quick to expose each of our existing domain objects as resources in a standard way, while still giving us flexibility to step out of that pattern if need be.
...