Create object via REST API with specified UUID

Here at PIH, we are working on a task to migrate patients from one instance of OpenMRS to another instance. We thought we would use the REST API to export the patient record to a JSON file and then import the JSON file on the destination system and create patient with demographics and encounters and visits via REST API.

It looks like the REST API does not support creating resources with a given UUID. Example: If I try to POST the following json to http://localhost:8080/openmrs/ws/rest/v1/encounter

{
	"uuid": "49F44F03-C16B-4562-8DDC-89D20093918B",
	"patient": {
	     "uuid": "5861aeea-c6d3-44f5-b016-07e78b4d1c3f"
	},
	"location": {
	     "uuid": "23e7bb0d-51f9-4d5f-b34b-2fbbfeea1960"
	},
	"encounterType": {
	    "uuid": "a8584ab8-cc2a-11e5-9956-625662870761"
	},
	"encounterDatetime": "2017-05-09T08:44:50.000-0400"
}

I get the following error:

{
  "error": {
    "message": "[Some properties are not allowed to be set: uuid]",
    "code": "org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource:625"
   }
}

because Encounter.UUID is not on the list of the CreatableProperties.

Hovewer, I could create a visit with the Encounter above and the created encounter would have the UUID that i specified in the JSON: POST http://localhost:8080/openmrs/ws/rest/v1/visit

{
      "patient": {
        "uuid": "5861aeea-c6d3-44f5-b016-07e78b4d1c3f"
      },      
      "startDatetime": "2017-05-09T08:44:50.000-0400",
      "stopDatetime": "2017-05-10T08:44:50.000-0400",      
      "location": {
        "uuid": "d6dafa1a-9a2f-4f61-a33e-410acb64b0e9"
      },
      "visitType": {
        "uuid": "f01c54cb-2225-471a-9cd5-d348552c337c"
      },
      "encounters": [
      	{
			"uuid": "49F44F03-C16B-4562-8DDC-89D20093918B",
			"patient": {
			    "uuid": "5861aeea-c6d3-44f5-b016-07e78b4d1c3f"
			},
			"location": {
			    "uuid": "23e7bb0d-51f9-4d5f-b34b-2fbbfeea1960"
			},
			"encounterType": {
			    "uuid": "a8584ab8-cc2a-11e5-9956-625662870761"
			},
			"encounterDatetime": "2017-05-09T08:44:50.000-0400"
		}
      ]
}

Peeking through the code it seems that it is by design that you cannot create objects via REST with a specified UUID? But, it is possible to create objects with specified UUIDs if they are children of another object. Is this correct? Is there a better way to create objects via REST with specified UUID?

Any other suggestions on how to migrate data from one OpenMRS system to another and persisting the UUID of the original objects?

Thanks!

1 Like

How about having a setting which turns this on or off?

We should allow for new objects to be created with a user-specified UUID.

I imagine it would be straightforward to implement this, though somewhat tedious because there are a lot of resources to modify.

(Maybe it’s enough to just add uuid to the createable properties of each resource, and ensure that uuid isn’t made an editable property.)

Hello, was there any progress on this? We are working on Sync 2.0 module and it is crucial for us to be able to create objects with given uuid. cc @pgesek @pkornowski

This would be a nice to have feature! We required this functionality in our mobile app to sync entities created offline to a running openmrs instance. Instead we created a work around, which works, but it would be better if uuids can be defined by a user.

Andrew

@darius @raff @mseaton Any thoughts?

If we were truly RESTful, this would be done with a PUT.

Agreed.

@jslawinski I would create a Pull Request with changes to the Resources that you are working on. If they get approved, the work can be carried over to the other Resource classes. Otherwise, this can be a big mountain to climb with no one willing to take the first step.

Andrew

I do not believe that any work was done on this. @cioan, did PIH do anything?

+1 to this. It’s behavior that we want to see, so go ahead and create it.

True. At this point we’re not supporting PUT for anything, and I would personally lean towards not adding it now just because I don’t want the Soldevelo team to be blocked on us discussing how to do this.

(I think it would be trivial to support PUT for creates, just by adding one method to the base REST controller. But the semantics of editing an existing resource via PUT is not so straightforward given our implementation.)

No, we did not work on this REST UUID issue.

This is coming up for us again… do we need a design call/approval to make “uuid” creatable (and not worry about PUTs for now) or can we just go ahead and do?

How did the Soldevelo team get around it?

(We are +1 for going ahead and doing it)

Take care, Mark

1 Like

+1 to making uuid creatable (via the standard POST to create a resource, ignoring PUTs). But not editable of course.

1 Like

PUT is the right thing to do, but we’ve never let doing the right thing stop us before.

Is it possible to code it as a PUT method and then add support for POST as a compromise? Or is our REST framework designed for POST & DELETE and support for other verbs (like PUT or PATCH) would take far more work? If it’s just the matter of choosing PUT vs POST in a method name or annotation, I’d favor using PUT and then adding a convenience method for POST to call the PUT method – support our hacky approach without punishing someone trying to follow REST conventions.

Earlier I said this:

Currently the way you create things is by POSTing to …/resource. I think it would be trivial to allow for create-via-PUT to …/resource/uuid without breaking anything.

I would add a new method in MainResourceController that:

  1. listens for PUT
  2. reads the UUID from an url parameter
  3. if that object already exists, fail* (for now, to avoid scope creep)
  4. otherwise, add the uuid to what was submitted via the body, and delegate to the existing create method

One caveat: this would probably require updates to the code that generates our swagger documentation. I don’t know how trivial that is.

* = PUT to an existing URI is supposed to overwrite the entire object, and it should be idempotent. Our whole framework is built around the idea that what you GET is often only a partial representation of the entire object, and when you do an update it only updates the fields you specify, it doesn’t blank out other fields. And our existing updates are not idempotent. Thus supporting overwrite-via-PUT would mean additional design, code, and test.

PS- I don’t actually think that adding PUT here will make our REST API easier for the consumer. Right now you can create a new concept via:

POST concept { ... }

The idea that you can create a concept with a specified UUID sounds like a secondary feature to me, thus it seems clear to me that we can document this as:

POST concept { uuid:"...", ...}

Having to document this as “in this other scenario, use a PUT instead, but we only support PUT for creates, not for overwrites” does not feel easier to me.

(But if we can make Burke happy with just a few lines of code, I’m fine with that.)

Was there any progress on this? This would be really helpful for us at Intelehealth for our mobile app for offline syncing of data captured and later on uploaded to an OpenMRS instance.

@jtrzebiatowski @burke @darius @mogoodrich

@ngoel2 are you looking for https://issues.openmrs.org/browse/RESTWS-729 and https://issues.openmrs.org/browse/RESTWS-752?

Both! Don’t see these in the API docs. Was this implemented using PUT or POST? How would we implement this?

@kundansinha

You can now POST with a uuid

Thanks @dkayiwa! If I wanted to update the API docs to reflect this, how would I do that?

@raunaq

Which one in particular are you referring to?