I’m trying to create a tool to quickly create a group of patients for use in the Group Sessions widget in use by ICRC. Broadly the task is to say “I want to create a new group”, set a group name, location, and select some patients which should be in the group. Here is what the mock up currently looks like
Currently there are two endpoints that this could be acheived with. POST ws/rest/v1/cohortm/cohort to create a cohort and POST ws/rest/v1/cohortm/ to add members to a cohort one by one after it is created.
I tried the first with body {“name”:“Magenta”,“cohortType”:“hello”} and got a response message: "[Some required properties are missing: location, definitionHandlerClassname, startDate]", and again with {"name": "Magenta", "location": "44c3efb0-2583-4c80-a79e-1f756a03c0a1"} and got response org.openmrs.module.webservices.rest.web.response.ConversionException: location on class org.openmrs.module.cohort.CohortM\n\tat org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource.setProperty(BaseDelegatingResource.java:800)\n\.... I could be using this endpoint incorrectly, but it is hard to tell from the current documentation.
Even if that endpoint was working, for the workflow for this feature to work it would require 1 network requests to generate a cohort, followed by N async requests to fill in members one by one. I believe it would be much cleaner to support a new endpoint which would be passed the cohort metadata and a list of members in order to create the cohort and make links in one request. This would serve a better user experience.
Generally, it’s pretty easy to create an endpoint that can take a set of sub-resources on creation. What’s harder to figure out is how things should work for updates. For example if you create a Cohort with cohortMembers: [a, b, c] and then later update the cohort with cohortMembers: [c, d] what’s the expected outcome? Do we:
Add d
Replace [a, b, c] with [c, d]
I’m not always sure what the right operation is. Right now, the 3.1.0-SNAPSHOT version of the Cohort module has an attempt to implement 2 above. Hopefully we can iterate a bit a figure out what makes sense here.
I hadn’t even thought of the update action. For that I would be in favor of option 2. if a cohortUuid is passed as a payload key the endpoint can recognize it as a “replace” action and updates using method 2 as you stated above.
Here’s what would make sense to me for a REST API’s behavior in managing a list of members:
Method
Behavior
POST
Add members. Anyone already in the cohort is ignored. Anyone already in the cohort, but not in the given list remains in the cohort – i.e., if you post [B,C] to a cohort containing [A,B], the cohort becomes [A,B,C].
PUT
Change memberships to the given list. Any members in the cohort and not in the given list are removed, any already in the cohort are left unchanged, and any new entries are added.
DELETE
Any members in the list are removed. Any members who aren’t in the cohort are ignored
To me, those semantics make sense, but only if we have a separate /cohort/12345/members resource. I might also swap the POST and PUT semantics, but I feel less strongly about that.
So, what makes the most sense to me is probably something like this:
POST to /cohort (i.e., Cohort create) we accept a members property to initially populate the cohort.
POST to /cohort/12345 should probably be treated as invalid.
PUT to /cohort/12345, if it takes a list of members should replace the members with the list (so any existing members not in the list are removed; any new members are added).
DELETE request to /cohort/12345 either does a soft-delete or hard-delete of the Cohort and consequently of the memberships. (I’m suspicious of request bodies being sent with DELETE requests).
If we want to get fancy with list management, we should probably look into supporting the PATCH verb and JSON Patch or XML Patch to describe the changes (add this member, remove that one, etc.).
But we’re also a bit constrained by what the REST module already supports…
Hello, The cohort builder’s save cohort also required the same behaviour. I created this thread and started working on this. But I’m still trying to understand how the O3 rest module works. So I might need some help.
During a call this morning @ibacher was saying that this might actually be supported already via cohortm/cohort endpoint, but wasn’t sure what the payload should look like. If anyone can post an example working request that would be sufficient to solve this . Bonus points for adding it to the documentation.
@zacbutko i have removed the requirement for startDate,cohortType,location,definitionHandlerClassname and therefore you show now be able to create the cohort and its members with something like below:
{ "name": "Name of the new cohort", "cohortMembers": [{ "patient": "432edc73-26be-433b-84e6-18341a87d994" }] }
Hi @dkayiwa , This endpoint is still not working on dev3.
Using a POST to https://dev3.openmrs.org/openmrs/ws/rest/v1/cohortm/cohort with body { "name": "Name of the new cohort", "cohortMembers": [{ "patient": "8648a68d-1d68-4293-9d1a-a7a188b91418" }] } raw encoding JSON format. (text also doesn’t work) gives 400 error
"error": { "message": "[cohortMembers on class org.openmrs.module.cohort.CohortM]", "code": "org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource:800", "detail": "org.openmrs.module.webservices.rest.web.response.ConversionException: cohortMembers on class org.openmrs.module.cohort.CohortM\n\tat org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource.setProperty(BaseDelegatingResource.java:800)\n\tat org.ope...
Wait, then I’m confused. Doesn’t that mean that the endpoint should be working now? I’m still getting a 400 for POST to https://dev3.openmrs.org/openmrs/ws/rest/v1/cohortm/cohort with error
“error”: {
“message”: “[cohortMembers on class org.openmrs.module.cohort.CohortM => patient on class org.openmrs.module.cohort.CohortMember => Privileges required: Get Patients]”,
“code”: “org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource:800”,