I just wanted to follow up on this thread. Our outreach team draws a map of where each patient lives when the patient is enrolled. This map is later used to track a patient who becomes lost to follow-up. We are hoping to include images of these maps in OpenMRS. We were hoping to use the rest api to get and post images to OpenMRS. But after reading this thread, it seems like this may not be possible? Anyone have any success use the REST API to get and post images without making changes to the core?
First of all there is no āimage REST resourceā, so the short answer is no.
However you can save images as complex obs of course. But I can say, for having played a bit with this for VDUI, that the current implementation of the obs resource doesnāt quite handle the case of complex obs. For instance we had to create a custom ComplexObsResource extending ObsResource to properly handle deletion and certain types of edits. See here.
By the way this example shows that you donāt really have to worry about (not the core but) the REST Web Services module, you can just add resources or extend existing resources through your own module(s) anyway.
In the context of VDUI I scratched my head a lot over this one: should I really be text book REST-compliant for the upload/download of the data behind the complex obs?
This would mean Base64-encoding/decoding all the time. At first I thought that there would be a performance issue, and there is one but I donāt think it is really meaningful. However for VDUI this option was not really working anyway since not every content can just be Base64-encoded, especially when you donāt know in advance which MIME types you will have to handle. And thatās the use case for VDUI: it implements the handling of certain MIME types in a specific way but otherwise it deals with the content in a generic manner.
But if you know that you will always deal with images, then you can certainly create - say - an ImageObsResource and ensure that POST, GET, DELETE⦠etc are implemented according to your needs.
Your use case suggests that a non-obs could perhaps do the trick, so you may want to investigate that one then!
I would be curious to hear about your findings.
Letās take another look at it. Weād like to implement RESTWS-297.
The approach suggested in the issue description and relevant issue in openmrs-api TRUNK-4964 doesnāt sound right to me.
I suggest not to use over-engineered dedicated handlers from openmrs-api and instead always use BinaryDataHandler to store files POSTed by regular HTTP means as multipart/form-data instead of encoding them in JSON payloads. Itās a client, who sends data and gets it back that best knows how to handle that data.
+100 for not over-engineering. However either with the multipart or the Base64 approach, I believe it requires changes in core and of course in REST due to the nature of POST (using reflection instead of static setters).
Side note: this is something we are going to need at PIH shortly as well. I need to catch up on this thread, but I tagged RESTWS-297 as something we could potentially work on during the OMRS16 hackathon.
Not all Obs use a binary data handler, so we canāt use a single handler to accomplish this, also note that Obs are immutable, it would be wrong to have to update them just to set the complex data since it would happen in a separate http resuest, one should be able to post an Obs along with its complex data in one rest call to avoid āupdatingā it which otherwise would result in a void and create new operation, for this reason we need to update the core api for it to be possible
If Iām understanding you right, this is a no-go. Concepts are free to declare any type of handler, and the REST API needs to support all of them.
I would think we must support a POST of json-encoded binary data (since this is the āeasiestā for a REST API client, right?), and we could also support multipart/form-data as a nice-to-have.
But the job of taking these posts, extracting the data, and streaming it to into the underlying Java API should be solvable purely in the REST module without needing to change the Java interfaces, right?
Also, creating or updating an obs with complex data should be doable as a single REST call that works atomically.
@darius or anyone who used handlers, would you care to explain what is the reasoning behind having different handlers in openmrs-api? Why do we need them? I donāt quite understand the concept behind themā¦
Hereās the only place where I found the usage of ImageHandler:
As it occurs to me in this example the only purpose of the handler is to indicate that it is an image. The methods implemented by the handler doesnāt seem to be used at allā¦
Anyway, I think I know how to handle it now and can do a first stub at implementing it. I donāt see a need to change openmrs-api at the moment to address the issue.
I think posting a file as multipart/form-data is easier at least from the javascript browser client. We can put json for obs metadata in the same request as multipart/form-data in the āobsā field to make the operation atomic.
Adding support for base64 json-encoded binary data should be easy as well, though it should be used for smaller files only as it increases bandwidth usage by ~30%.
When we save an image, although only one file is provided to the backend, we generate one more out of it as a compressed thumbnail file that is saved alongside the original image.
But we needed another handler for cases where we donāt generate any thumbnails, the non-image cases.
You may also think of cases where one uses handlers to do something else than saving to disk or fetching from disk. Imagine a handler that posts to a third-party service and fetches from it.
@raff, youāre not wrong to say that the ComplexObsHandler interface is overengineered.
The key historical point is that Burke designed it long long ago (before 17 Aug 2010, when we switched from Ant to Maven). The intention was that intelligent handlers for different datatypes in the API could support multiple views in different UIs.
(It holds up pretty well for having been written >6 years ago.)
It works for all handlers, which accept and set InputStream in ComplexData.data (at least all in openmrs-api do) when requesting RAW_VIEW.
Please see 2 tests presenting possible POSTs. One is for embedding base64 encoded data in json and the other is for uploading a file. You always fetch a file by requesting /obs/{uuid}/value.
Thanks @raff! We have a contractor working on some upload functionality that will will need this in the near future, so we will let you know how it goes!
Great @raff, I like a lot that youāve gone through the two possibilities: (1) either everything embedded in the JSON or (2) any byte array added as a POST request file alongside the JSON.
In the latter, could you explain how this new upload(..) method is triggered even though you simply save the complex obs through the usual URI?
Is it Spring that knows that if the input is a MultipartFile then it has got to be the only possible route since thatās the only method having this type as an argument?