Fetching complex obs's data via Angular/REST?

Hi all,

The documentation points to using ImageHandler to get the ComplexData out of a saved complex obs (images in my case). So I registered ImageHandler with the concept complex that I use to save images. But how does that fit with REST webservices? Is there any service out there that would return the complex data when provided a complex obs’s UUID?

When using uicommons’s Angular wrapper for the obs REST service, I only see this as the value:

Which is generated by ImageHandler and is my image’s metadata, but how do I get back the image as a byte[]?

I have already looked around a little but Bahmni doesn’t seem to be using complex obs, and openmrs-module-patientimage uses person attributes.

Thanks for your help!

It’s not possible currently, see https://issues.openmrs.org/browse/RESTWS-297

I don’t think ImagenHandler can help you in any way. The obs services requires an input stream to be open in the controller, the key point is how to obtain the binary contents from the JSON payload (my proposal was to send it Base64 encoded).

1 Like

But is there somewhere a web service that could already do that? Even if it is not RESTful then, for the time being. By ‘that’ I mean returning the saved complex data given the obs UUID? Look at what is suggested in this article (‘Complex Obs Support’) under WebImageHandler. Isn’t that what this ComplexObsServlet already does?

Note that I have already handled the upload, and I’m not using any existing REST service indeed. I have implemented my own controller receiving a MultipartFile from the client. I was just wondering if there was a way to get back the saved complex obs? It seems that RESTWS-297 is about saving a complex obs.

@mksd, yes, the legacy UI has a way to fetch a complex obs’s binary data. You can probably do this from the servlet you have linked to.

I suppose you can use the existing servlet for retrieving the complex obs data. IIRC there was a controller to save the obs but I can’t find it in core (nor the JSP).

@lluismf just incase you forgot, we moved those to the legacyui module. :slight_smile:

1 Like

Yes I forgot. Maybe the complex obs servlet could be enhanced to support saving complex obs.

I am mildly keen on bringing a dependency on openmrs-module-legacyui just because of this servlet. I may just then copy the parts that I find useful for our use case. But thanks for confirming that this servlet is indeed the way to go, as per the current state of things.

@darius, @lluismf, I could look into bringing the missing bits in openmrs-module-webservices.rest if you could point me in the right direction.

The servlet already exists in core but only implements doGet (not doPost). To reuse the post then you need the controller in legacyui (or create your own). That’s why it seems interesting to add a doPost in the complex obs servlet.

There was a discussion months ago about how to implement this in REST but no agreement was reached. IMO passing the contents in Base64 is easy (but slower). To be honest I don’t really know what’s the best solution to send binary data in a REST call.

Unfortunately ComplexObsServlet takes an internal obs ID as an input parameter. Is there a simple way to get an obs’s UUID from its internal ID? I don’t seem to find the internal ID anywhere in the full JSON representation of an obs.

Nevermind, this is exactly what I needed:

ObsService.getObs({
  patient: $window.config.patient.uuid,
  concept: $window.config.conceptComplexUuid,
  v: 'custom:(obsId:ref)'
}).then(function(obs) {
	...
})

:slight_smile:

@lluismf, am I correct to assume that you would not save the Base64 encoded string to disk? So the upload steps would be

  1. Send JSON payload to server.
  2. Decode Base64 string to byte[].
  3. Save byte[] to file on disk.

And of course similar steps the other way around when fetching the images.

Actually it would be simpler, just open a stream (Base64InputStream?) and invoke the Complex Obs API that will do this work for you (reading the stream and creating a file in the complex obs repository).

Using BinaryStreamHandler, correct?

I don’t think so, check the complex obs servlet I believe there is a service to save the obs. The REST resource can use the same logic.

The problem with doing this in a generic way, is that you need to know the mimeType of the incoming stream or Base64. It may not always be an image and there may not be an appropriate xxxHandler for it. I think our approach of using a xxxHandler was an example of over-engineering. It should be left to the client to provide the Accept type and open the complex obs in any way that they can. The server doesn’t need to know what Handler is required. I recommend that you use something like Apache Tika, to detect the stream and set the appropriate contentType when sending the complexObs

Thanks guys for your input. Whilst developing a Patient Images module I was wondering whether I should try to make it as REST/JSON friendly as possible, hence this thread. But I won’t go down that route, I am just extending core’s ImageHandler and using a custom PatientImageComplexData and that is enough for now and for our needs.

I saw that from core 1.12+ ComplexData holds a mime type member, which is something I needed and that I added to my extending class. (Q.) Any chance that this could be backported to 1.11.x?

@sunbiz, I came across Apache Tika too and I eventually settled for a quick workaround without using it, and that was enough for our needs. However when I was working on the content type detection (and mapping to file extensions) I wanted to bring it as a dependency and I was hitting this issue that it was not found on OpenMRS Nexus repo.

On our organization we are trying something similar. We want to connect a third party desktop application (Ultrasound Image software) with OpenMRS, so everytime we obtain an ultrasound image from pregnant women, the third party software would store (upload) this image on a OpenMRS database associating it with the encounters, patients, … we previously created. Our first approach was to do this through the REST API (GET would obtain info about the person and concept uuids and POST would create the obs), but after reading the whole thread doesn’t seem to be a good approach anymore. So my question is, how is the easiest way to achieve this in your opinion?

The only reason why I am turning away from REST is because I have extended core’s ImageHandler, and ImageHandler saves images (byte[]) on the disk. The consequence is that wiring Base64 encoded JSON payloads between server and client would require encoding and decoding those images every time they are being manipulated. After a quick trial on the download side only, I found that the performance loss was not worth it at all.

However, if you don’t care about ImageHandler and that you use some other handler that somehow saves the Base64 encoded content on the disk, then you can certainly go that way. Be advised that there is currently no REST POST interface to do so, but it is fairly trivial to implement it anyway. At least it was really trivial to implement it for GET when I was experimenting with it.

Thanks for your reply. In that case we will start our tests on that direction.