# REST API for creating compositions with id **Category:** [ITS](https://discourse.openehr.org/c/its/41) **Created:** 2021-11-26 03:46 UTC **Views:** 1341 **Replies:** 52 **URL:** https://discourse.openehr.org/t/rest-api-for-creating-compositions-with-id/2113 --- ## Post #1 by @Dileep_V_S The current REST specifications does not seem to support creation of compositions by passing an id (similar to creating ehr with id). Is there any plans to support this feature? This will be useful in situations when migrating data from one CDR to the other. Creating new compositions ids can have implications as the id may be referenced within and outside the CDR and will all need to be updated. regards --- ## Post #2 by @pablo I think this is a case for the IMPORTED_VERSION class (https://specifications.openehr.org/releases/RM/Release-1.1.0/common.html#_overview_5) which I don't think is well supported by the current API, at least there are no clear use cases for it. Though I don't have strong opinions, I think this use cases shouldn't be part of the normal clinical flows API, but of an administrative API, because the use case is importing documents from another CDR, which is an administrative task, not directly related with the health care process. --- ## Post #3 by @jake.smolka Technically you can post a custom composition ID within the body of the POST, see: https://specifications.openehr.org/releases/ITS-REST/latest/ehr.html#composition-composition-post But it depends on the implementation on how it is processed and if it is actually persisted. There was some discussion about that topic some time ago and whether or not it should be more streamlined. Simply put, either if this possibility should be removed from the REST spec or if it should be made mandatory option for implementers IIRC. Does anyone happen to know where we discussed that? --- ## Post #4 by @sebastian.iancu We could discuss about relaxing conditions for PUT (now used to "update" only) so that you can also create a first version and store it under that id, ... but that id should be the same as the one in composition.uid. @Dileep_V_S , is that not possible for you to place/set the id in the composition and then just use POST? If you would need the use-case described by Pablo, you could use the [ehr's contribution-post](https://specifications.openehr.org/releases/ITS-REST/latest/ehr.html#contribution-contribution-post), or perhaps you could propose to support POST/PUT on [versioned_composition](https://specifications.openehr.org/releases/ITS-REST/latest/ehr.html#composition-versioned_composition) - as far as I remember we did not had that use-case yet. --- ## Post #5 by @Dileep_V_S EHRBase seems to ignore this and create a new id. [quote="jake.smolka, post:3, topic:2113"] Simply put, either if this possibility should be removed from the REST spec or if it should be made mandatory option for implementers IIRC [/quote] +1. The specs should remove the ambiguity for implementors. I personally feel that we should allow this either in POST or PUT. --- ## Post #6 by @sebastian.iancu Can you you elaborate a bit on what is the ambiguity that you think should be removed? --- ## Post #7 by @Dileep_V_S [quote="sebastian.iancu, post:4, topic:2113"] We could discuss about relaxing conditions for PUT (now used to “update” only) so that you can also create a first version and store it under that id, [/quote] It will be good if we do that as it improved flexibility for deployments to evolve and refactor content as they mature and grow. However, we may need to consider some possible situations and cover for it. Do we allow versioned composition IDs? if yes how do we allow newer versions to be committed without the older ones? How do we ensure system integrity in that case(openEHR systems are supposed to maintain versions) as he target CDR will not have the older versions? [quote="sebastian.iancu, post:4, topic:2113"] you could propose to support POST/PUT on [versioned_composition](https://specifications.openehr.org/releases/ITS-REST/latest/ehr.html#composition-versioned_composition) [/quote] Where can I do that? --- ## Post #8 by @Dileep_V_S The POST composition example body contains this ``` "uid": { "_type": "OBJECT_VERSION_ID", "value": "8849182c-82ad-4088-a07f-48ead4180515::openEHRSys.example.com::1" }, ``` That would imply that you can pass versioned composition ID in POST. But the description does not make it clear whether it will create a new composition or create one with the ID passed. Also, if the passed version ID is used, then can that be any version or should it be only version 1? --- ## Post #9 by @sebastian.iancu [quote="Dileep_V_S, post:8, topic:2113"] That would imply that you can pass versioned composition ID in POST [/quote] Indeed [quote="Dileep_V_S, post:8, topic:2113"] But the description does not make it clear whether it will create a new composition or create one with the ID passed. [/quote] Yes, that might need better clarifications. But the principle is that if possible, the server will create a (first version of the) composition with the ID passed, or respond with a status error in case of ID-conflict (this is however not yet specified, but I guess would be 409) or other kind of exception (invalid content, invalid ehr_id, etc). [quote="Dileep_V_S, post:8, topic:2113"] Also, if the passed version ID is used, then can that be any version or should it be only version 1? [/quote] We did not discussed in SEC about use-case when the first version is not that with id=1, but I don't see any impediment there: by default, the first version is 1, but i guess you may choose to start with another higher number, as long as you'll the build a lineage in version history. Some refs: [Common IM - local_versioning](https://specifications.openehr.org/releases/RM/latest/common.html#_local_versioning), [base_types identification_of_versions](https://specifications.openehr.org/releases/BASE/latest/base_types.html#_identification_of_versions) and [base_types version_tree_id_class](https://specifications.openehr.org/releases/BASE/latest/base_types.html#_version_tree_id_class). --- ## Post #10 by @sebastian.iancu [quote="Dileep_V_S, post:7, topic:2113"] Where can I do that? [/quote] If you have a JIRA account you can do it in the SPECPR and use "ITS - Rest APIs" component please - see [https://specifications.openehr.org/releases/ITS-REST/open_issues](https://specifications.openehr.org/releases/ITS-REST/open_issues) ![image|509x500](upload://iaIdWddNLumADsJhiQNCtvDNEqT.png) --- ## Post #11 by @jake.smolka [quote="sebastian.iancu, post:9, topic:2113"] Yes, that might need better clarifications. But the principle is that if possible, the server will create a (first version of the) composition with the ID passed, or respond with a status error in case of ID-conflict (this is however not yet specified, but I guess would be 409) or other kind of exception (invalid content, invalid ehr_id, etc). [/quote] This is what I meant we have discussed. And I actually found the ticket now: https://openehr.atlassian.net/browse/SPECITS-62 So this topic is indeed not clarified and there's no specified behavior yet. --- ## Post #12 by @sebastian.iancu @jake.smolka you are right, and @Dileep_V_S issue is closely related to this issue. But in my impression we don't have an agreement yet on the solution for that ticket, still in the investigating phase. So more feedback/thoughts are welcome. --- ## Post #13 by @Simon Hi all, We are currently working on a project which involves the export and import of compositions from CDRs. I have made the necessary changes to ehrBase to allow us to do this. We've had a few issues but overall it seems to be working ok. @ian.mcnicoll we need to move this discussion on, as the ehrBase team are waiting on changes to the standard before they make code changes. Finally, I am confused as to why importing/exporting doesn't happen at the contribution level, however there doesn't appear to be away to simply retrieve all the contributions for an ehrId, am I missing something ? --- ## Post #14 by @thomas.beale [quote="Simon, post:13, topic:2113"] the ehrBase team are waiting on changes to the standard before they make code changes [/quote] Do we know what specifically they are waiting on? [quote="Simon, post:13, topic:2113"] I am confused as to why importing/exporting doesn’t happen at the contribution level [/quote] Do you mean EHR Extract import / export? [quote="Simon, post:13, topic:2113"] there doesn’t appear to be away to simply retrieve all the contributions for an ehrId, am I missing something ? [/quote] That would be easy for any implementation to do, but I'm interested to know why just obtaining Composition Versions is not sufficient. --- ## Post #15 by @stefanspiska @thomas.beale @Simon We would implement the solution which would check if the submitted composition has an uid set. This also would work for flat "international_patient_summary/_uid": "c5db0694-5cd2-4fd1-a5bf-ed25f1c5d371::ehrbase.org::1". This makes the most sense and don't require a change in the API. --- ## Post #16 by @ian.mcnicoll I'd be happy with that. I think it is clear enough. Is anyone pushing hard for PUT /composition? I don't understand why this is more Restful since we are not updating an existing composition, in either of the use cases described. --- ## Post #17 by @ian.mcnicoll [quote="thomas.beale, post:14, topic:2113"] Do we know what specifically they are waiting on? Decision on how to create a new composition but with a provided uid. [quote="thomas.beale, post:14, topic:2113"] That would be easy for any implementation to do, but I’m interested to know why just obtaining Composition Versions is not sufficient. [/quote] Yes but its just not supported in the REST API. Why are composition version not enough? Good question which we discussed internally . The context is bulk transfer of contents of one CDR to another, preferably using standard REST API calls 1. Templates are easy 2. EHR is easy 3. Need a way to retain composition UIds so that internal references and links don't have to be recreated/ hooked up (so the need for the composition call that supports inected composition UID on create) 4. Maybe it is just a case of reading and cloning each composition version in the new CDR but we felt that we should try to retain the contribution wrapper particularly where there might be eg an addition, a modification and delete, all in the same contribution, so that the rollback capacity would not be lost. If we do recreate the contributions, I'm still a little hazy on the need to retain any internalIds, even the contributionId itself- are these ever referenced i.e what would happen if we just regenerated new uids (other than for compositions) ? or do we need a way to clone a contribution retaining existing Ids? --- ## Post #18 by @ian.mcnicoll Maybe we should move the Contribution / export-import discussion to a new topic? I t would certainly be very col to demonstrate how this works in terms of vendor/tech neutrality of CDRs --- ## Post #19 by @thomas.beale [quote="ian.mcnicoll, post:17, topic:2113"] context is bulk transfer of contents of one CDR to another [/quote] Yes, well I did have some reasons of my own, this is the main one. So what you really want to do is rewind a series of full commits done to an EHR inside one CDR onto an EHR in the other. [quote="ian.mcnicoll, post:17, topic:2113"] Maybe it is just a case of reading and cloning each composition version in the new CDR but we felt that we should try to retain the contribution wrapper particularly where there might be eg an addition, a modification and delete, all in the same contribution, so that the rollback capacity would not be lost [/quote] You definitely want this. What I would suggest is that the contents of each Contribution in the source system be worked out, and then the commit contribution call be used in the target system to apply that set of versions as a new Contribution. It's risky to assume that exactly the same commit structures will work in a target CDR, unless it's exactly the same software, and no local config differences could modify it (even something dumb like locale-specific markers). Also, you need to be careful on commit times in the target system. If you don't call a commit function, but instead try to paste the data representing the Contribution straight in, the commit times will actually be wrong on everything, since these commits are being done 'now', not when they were done in the original system. In this case, the Contributions will get new UIDs, but the Compositions can retain what they have. I am talking here of single EHR kind of transfers. If you are talking about essentially copying the entire contents of a CDR to another (say, a more recent version of the same product, whose installation should be invisible to users) then a low-level direct copy will potentially make sense. --- ## Post #20 by @Simon I wrestled with that idea but I discounted it because if I add it as a parameter on an API I am explicitly stating that I want to preserve the composition Id, if you just consume it from the composition itself then its easier to do it accidentally. I guess it'll need lots of documenting... --- ## Post #21 by @ian.mcnicoll I've read up a bit more and using PUT just gets us potentially into a tangle with th e url path or complexities around headers. From my reading of the RESTful difference between PUT and POST, this is still a POST. https://restfulapi.net/rest-put-vs-post/ We are adding a new unique resource to the collection of Compositions, not updating an existing composition. The only difference is that we are assigning the uid client-side, not server-side. The only downside I can see of using the uid within the Composition body, is that some composition generated examples populate the uid, which might cause confusion, so I'd want that behaviour to change. --- ## Post #22 by @ian.mcnicoll We are looking at full vendor to vendor transfer of all EHRs. This would obviously be more efficient at lower level but may not be a high priority for CDR vendors to implement, so this was an experiment to see how much could be done with the standard API. If nothing else it is a good advert for tech/vendor neutrality in a way that is non-opaque, and helps tease out the exact requirements. Good point re the commit_time - we need to think about that. --- ## Post #23 by @damoca That's an interesting scenario, and probably needed sooner than later. Since different vendors can implement different persistence technologies, its reasonable to work it out at the API level. But it's not only about copying parts of the loaded EHRs. As @thomas.beale said, you should replicate all metadata (commit times, etc.), templates loaded, FOLDERs, CONTRIBUTIONs, demographics, and any other configuration at the EHR level. The solution probably is to design a dump/load API endpoint, having some kind of container for all that information. Maybe the EHR_EXTRACT class, or an evolution of it, could be a good candidate. This would be computationally heavy, but that's another topic :smile: --- ## Post #24 by @ian.mcnicoll We are hoping to cover eerything in there other than Folders and Demographics as neither are included in our current scope. Folders would probably not be too hard to do but there really are very few ? any independent openEHR Demographics services out there, and in any case, at least right now very loose or non-standardised coupling. But we are doing/ havedone Templates Ehrs Contributions Composition versions Agree that ideally this should be nicely wrapped up in to a simpler service but for now it is probably pretty useful to see the moving parts, if only so we can raise some of these issues as we go along. If we can agree on the post /composition with uid resolution and have a list contributions end point, we are probably very close to having something working. I see we, I mean the Future Perfect guys like @Simon !! I'm just giving a little advice. --- ## Post #25 by @Seref [quote="damoca, post:23, topic:2113"] The solution probably is to design a dump/load API endpoint, having some kind of container for all that information. Maybe the EHR_EXTRACT class, or an evolution of it, could be a good candidate. [/quote] This would be my preferred approach to design. Even though we did not explicitly define it, there is an implicit context to the operations supported by the REST API (or so I think). Restoring data from another CDR is a richer operation in terms of its semantics, we're replaying an actual insert that took place in another CDR, and there is more data that is of interest than a direct call to a REST endpoint, say from a mobile app. The time of the original operation (as Tom points out), the fact that this operation is a replay of a previous one, and the time of the replay (which is potentially meaningful for audit purposes), and the information related to the original CDR. The identity of the bulk import itself, to be assigned and tracked, so that we know how many succeeded, failed etc. The need to keep the original uids. I would not like to encode all of this within the semantics of a single REST endpoint, it's too big of a semantic overload for my taste, due to current REST apis not having any awareness of a bulk operation (this is PUT/POST 16 of 345,000... -> where do you keep that info? REST is supposed to encapsulate the whole state in the call.) Finally, things get interesting when you scale up to tens of millions of compositions. We're currently planning a data migration between two Ocean systems which will take days using specialised tools. If it was REST endpoints, we'd be pronouncing months... --- ## Post #26 by @ian.mcnicoll Totally agree but both for immediate need and for education and a bit of 'look how easy this actually is', still keen to show the moving parts via chained REST calls. @Seref - what's your take on POST vs. PUT for creating new compositions with a given uid, which has wider uses-cases than this one e.g. linked compositions within a contribution. Can we continue this specific discussion in JIRA https://openehr.atlassian.net/browse/SPECITS-62 and hopefully reach consensus. Every one seems to agree it is a reasonable idea --- ## Post #27 by @thomas.beale [quote="ian.mcnicoll, post:22, topic:2113"] We are looking at full vendor to vendor transfer of all EHRs. This would obviously be more efficient at lower level but may not be a high priority for CDR vendors to implement, so this was an experiment to see how much could be done with the standard API. [/quote] [quote="damoca, post:23, topic:2113"] The solution probably is to design a dump/load API endpoint [/quote] This is definitely a dump/load thing. Some initial modelling on the abstract version of that [here](https://specifications.openehr.org/releases/SM/latest/openehr_platform.html#_admin_service). The reason why it has to be done as a dump-load service is to allow for differences in concrete data representation inside CDRs of different vendors and even different releases from the same vendor. No vendor would be able to guarantee anything if someone just slides the DB tables or even full JSON dump straight into the target DB, even if in some cases it might work. The creation of Versions and Contributions has to be done by appropriate calls taking the relevant content as an argument. There are clearly multiple forms of this: * a partial EHR extract -> import (e.g. as for transfer of care) - this is a merging scenario and you might want to preserve original commit times if the source and target CDRs are within the same health service, or you might not, if the patient treatment is now being taken over at the destination. * the dump-load situation for a whole CDR's contents, to upgrade it in situ to a new CDR - preserve original commits * dump-load of a full EHR from one CDR to another one - probably want new commit times, indicating the earliest time the local staff at the destination could have seen the data. * etc. These correspond to real world scenarios like: * merging a piece of an EHR to a CDR in a new location * moving an entire EHR to a CDR in a new location (for patient move, e.g. new country, region etc) * replacing the CDR in situ, data should look the same as before [quote="Seref, post:25, topic:2113"] I would not like to encode all of this within the semantics of a single REST endpoint, it’s too big of a semantic overload for my taste, due to current REST apis not having any awareness of a bulk operation (this is PUT/POST 16 of 345,000… → where do you keep that info? REST is supposed to encapsulate the whole state in the call.) [/quote] I agree. --- ## Post #28 by @damoca [quote="ian.mcnicoll, post:26, topic:2113"] Totally agree but both for immediate need and for education and a bit of ‘look how easy this actually is’, still keen to show the moving parts via chained REST calls. [/quote] Of course, and what you say is a totally needed approach. Anything else we could propose now would not be available for several years. @Seref I was not talking of any specific solution at this point, just talking about how to approach to this problem. Then there will come the technical problems, and the possible solutions: * Probably we are not talking of a REST transfer of data, but an export to some kind of file. Or maybe communication via other formats (protobuf). We could also consider using a compression format to reduce the size of data. * Probably this is not a single method, but has more granular operations. * We can learn a lot from SQL dumps: we could allow to decide to export just the "schema" (templates, etc.) or the schema + data. Or just the data for some templates or patients. And for sure, there will be many other optimizations. --- ## Post #29 by @sebastian.iancu As mentioned in the past, in the context of https://openehr.atlassian.net/browse/SPECITS-62 issue, I'm still in favor of extending the semantic of our `PUT Composition` to be used also for creation, not only for update. This would be in line with https://www.rfc-editor.org/rfc/rfc9110#section-9.3.4 and is most likely exactly what a programmer using REST Api would expect from openEHR API. The `PUT Contribution` should be also changed to support creation of a Contribution with a given `uid`. We should also keep this behavior consistent, and specify PUT for all resources working in the same way (i.e. create & update). These changes will be done in the upcoming REST Api specification release, and should facilitate most of replay-functionality described above, keeping original IDs in the target system, although I can imagine system creation timestamps might be not honored always - which is an aspect we should still can discuss in the SEC meetings. --- ## Post #30 by @stefanspiska @sebastian.iancu The composition uid is just the https://specifications.openehr.org/releases/RM/latest/common.html#_locatable_class locatable uid. so Its a bit strange that one is special and needs a specific syntax. Also a use case we have is to create a composition and then add it to the directory in one contribution, which only possible if you can set the uid in the composition in the contribution and then put the uid in the folder update in the same contribution . --- ## Post #31 by @thomas.beale [quote="stefanspiska, post:30, topic:2113"] Also a use case we have is to create a composition and then add it to the directory in one contribution, which only possible if you can set the uid in the composition in the contribution and then put the uid in the folder update in the same contribution [/quote] I don't see any reason in principle not to allow this, as long as UUID generation rules are being followed by the client. Here's a [nice article on UUID generation](https://digitalbunker.dev/understanding-how-uuids-are-generated/). --- ## Post #32 by @ian.mcnicoll [quote="sebastian.iancu, post:29, topic:2113"] This would be in line with [RFC 9110: HTTP Semantics ](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.4) and is most likely exactly what a programmer using REST Api would expect from openEHR API. [/quote] (clinical hacker alert!) I looked at [RFC 9110: HTTP Semantics ](https://www.rfc-editor.org/rfc/rfc9110#section-9.3.4) ands I could still not see a a good argument for using PUT. Can you point to the exact part of the spec which make you think PUT over POST? I can see that a create is allowed by PUT but the spec does not explain why or when it is preferred. We are definitely creating new resources here, not re-allocating uids to an existing resource (or at least that's my reading!) The requirements for POST seem fully met and those specs dod not help me understand where a create might be reasonable --- ## Post #33 by @Seref [quote="damoca, post:28, topic:2113"] @Seref I was not talking of any specific solution at this point, just talking about how to approach to this problem. [/quote] Sorry if I failed to express myself. To clarify: I didn't think you were suggesting a specific solution :) I just thought your diagnosis was correct, then moved on to a particular suggestion of mine. Based on your follow up, I get the feeling we're on the same page, or maybe I'm confused ;) --- ## Post #34 by @Seref [quote="ian.mcnicoll, post:32, topic:2113"] I could still not see a a good argument for using PUT. [/quote] This is where angels and pinheads emerge I'm afraid. Is http semantics to be taken directly as REST semantics? Http has no problem using put for a creation while indicating the id to be created, but my understanding of REST favoured POST for that. I have to repeat though, I don't think it is a good approach overloading the REST api for bulk transfer semantics, but having said that, if we're talking about setting the identifier of a resource on the caller side, I'd be inclined to use `POST` with the id included in the resource contents, which is what `uid` gives us. That is slightly better then `PUT` in my humble opinion because it stick to create semantics of `POST` rather than resorting to `PUT`, which is acceptable but not as obvious as `POST`, but as I said, feels like angels and pinheads to me. Also in `PUT` scenario we have to make sure the id in the URL and the one in the body match, which is more moving parts then I like. The real question I have with setting the ids is: what about versioning? This pops up every now and then and there are discussions about this somewhere here: the uid field is set to a type relatively higher up in the identifier type hierarchy from RM, but in reality it is a more concrete type, set by a convention of Ocean's first use and everybody else following track (vendor see, vendor do) As in: ![image|546x91](upload://yxpExYmG6O4SP8NQfvbUMY5WvxB.png) First of all, how will we deal with system id and version when pushing a composition from another CDR via REST? if we use the `object_version_id` then I remember `:` not being allowed on some frameworks for being a reserved character in an URL (not a problem in POST). Then comes the versioning. What would the server do if you want to replicate the history of a composition (all versions) and you push `v1` after you push `v2`? Assume the DB timed out under heavy write load while trying to grow the db file size (yes, it happens) and v1 insert failed but v2 worked. Now you have some missing history which you have to fix. Then there's other invariants such as the contribution and folders as @stefanspiska mentioned. Since the id of the resource is overloaded in reality with more information than you can represent with REST's built in constructs as is the case here, we'll have to define a lot of situations with headers at the minimum. As in server behaviour when the above out of order insert happens. I'm not writing all this to be purist or pedantic. Maybe I'm missing the point but all of the above is pointing at REST just not having the semantic bandwidth IMHO. [quote="ian.mcnicoll, post:26, topic:2113"] but both for immediate need and for education and a bit of ‘look how easy this actually is’, still keen to show the moving parts via chained REST calls. [/quote] Well, I'm afraid I'm under the opinion that it actually is not easy. I give @thomas.beale a lot of grief when it comes to (over)pragmatism on my part but I don't think this is a case **you** can cut corners: you in bold because then it'll become "this is how it's done in openEHR "because Ian McNicoll did it that way. Same goes for other highly visible personas of openEHR btw. There's valuable work and lessons to take from FHIR here, who went with some file exports for bulk data transfer if my memory is correct. I hope I could make your day once again Ian ;) --- ## Post #35 by @ian.mcnicoll Thanks Seref, - mostly :wink: POST vs. PUT - thanks for the clarificaiton that this is quite a tight decision. We need to make a decision on this regardless of the bulk transfer usage as it is needed, particularly when constructing links within a contribution as @stefanspiska And I agree that we need something similar for Contribution, which retains existing identifiers, though I'm not clear if anything breaks if these are re-created. The way we planned it was basically to re-play each original Contribution, and each ascending version in the correct order but I can see the value of additional checks both that the uid does not already exist, and that the version is not out of order. As I understand it , retaining the original systemId is not a problem. In terms of failing commits, for whatever reason, I'd expect a whole Contribution would fail and be logged, whether that means the whole EHR should be deleted is an interesting question. I completely agree that this is not likely to be a good solution for anything other than small-scale use-cases / experimentation but of nothing else we are forcing the community to address some of these questions re Contributions, version order, fail behaviour, which would equally apply with a more elegant Bulk Import/Export process. And as a test of whether there are indeed 'corners being cut'. --- ## Post #36 by @sebastian.iancu Sorry @ian.mcnicoll for late reply (with answer to your question above), but here is the way I see it: - POST: you create a new resource by POSTing against a collection url, so you basically add (create) a composition to the EHR-composition-collection, and rely on the collection "manager" (i.e. EHR) to assign and return you an identifier for your composition. Thus the server-side will assign the uid. - PUT: you should use when you want create a resource and you want to be in charge of (or actually you have requirements regarding) the identification of your composition within the collection. Basically the client-side decides the uid. In both situations the server may refuse to execute the operation (to create the composition) if certain condition are not fulfilled. Consider here conflict on uid, version mismatch, etc. So, I would say you should use PUT only if you need a specific uid, otherwise use POST. The bulk import/export might be a use-case (although as mentioned above not performant enough for large replay cloning CDRs), or another use-case could be the one of creating compositions & associated folder with or without a contribution (and operation orchestrated by client-side). This is just http/rest - we might not like it enough, or we might say that is unhandy or not reach enough in semantic, but this is "standard", and programmers likes it (I guess...). Btw, FHIR also supports it - see [FHIR Http 3.1.0.4.1 Update as Create](https://www.hl7.org/fhir/http.html#upsert). --- ## Post #37 by @sebastian.iancu [quote="Seref, post:34, topic:2113"] The real question I have with setting the ids is: what about versioning? [/quote] I agree there is a lot of things we can discuss on this subject of system& versions & identification, and a lot o points where API implementation might go wild with subtiel flavors. But on the other hand for PUT (with an uid), is it not simple like this: - if no If-Match header is set, and uid is not allocated it will be version=1 (or the one specified), thus a create. - if you need to create a new version, make sure the payload and the headers are right so that operations will be an update (of the previous)? We could ask to rely only on POST to honor client-side uid, just based on payload (composition.uid), but that will make the spec unpredictable for a "REST API programmer. I'm afraid in that case we'll go against the mainstream - but please correct me if I'm wrong about this practice. Btw, in case of POST, FHIR ignores the id from the resource - see [FHIR Http create](https://www.hl7.org/fhir/http.html#create). --- ## Post #38 by @Seref [quote="sebastian.iancu, post:37, topic:2113"] I’m afraid in that case we’ll go against the mainstream - but please correct me if I’m wrong about this practice. [/quote] Frankly: I don't know. I don't think using POST with an id in the body would violate the so called REST principles but it may be non-idiomatic, so these are all grey areas. Your suggestions re headers is what I was referring to, and thinking about this clearly, I realised it actually follows a design principle from programming and api design I noticed, though I have not seen this named specifically: make the non-obvious harder than obvious :) So using `PUT` with well documented and quite possibly custom headers to define behaviour for edge cases etc, we can support creating resources with caller-set identifiers, versions etc. It won't be as easy to use as `POST` but that's actually the point. This works rather well in programming language and API design, 80-90 % of use cases are conveniently supported out of the box in terms of syntax/tooling etc, and when you need the remaining cases, you need a strong cup of coffee and some documentation. Thanks for pointing out what FHIR has done, I respect the effort they're putting into their work and where possible we should learn from them, so in this case support in favour of `PUT` becomes stronger for me. --- ## Post #39 by @ian.mcnicoll Thanks Seref / Sebastian, I'm also gently persuaded towards PUT by knowing that is the current FHIR approach, however ... @Sebastian - are you suggesting that for PUT https://{baseUrl}/v1/ehr/{ehr_id}/composition/{uid_based_id} the meaning of the {uid_based_id} is dependent on the existence of the IF-MATCH header? That feels a little tricky to me , as a common problem for newbies will be to forget toadd If-Match when trying to to a 'normal' PUT on an existing composition. Also to @stefanspiska question about Contributions - how would that work, as within the Contribution there might be a mix of creates and updates. ```json { * "uid": { * "_type": "UID_BASED_ID", * "value": "6cb19121-4307-4648-9da0-d62e4d51f19b"}, * "versions": [ * { * "preceding_version_uid": {}, * "signature": "string", * "lifecycle_state": {}, * "attestations": [], * "data": { * "archetype_node_id": "openEHR-EHR-COMPOSITION.encounter.v1", * "name": {}, * "uid": {}, * "archetype_details": {}, * "language": {}, * "territory": {}, * "category": {}, * "composer": {}, * "context": {}, * "content": [ ]}, * "commit_audit": {}}], } ``` --- ## Post #40 by @sebastian.iancu [quote="ian.mcnicoll, post:39, topic:2113"] PUT https://{baseUrl}/v1/ehr/{ehr_id}/composition/{uid_based_id} the meaning of the {uid_based_id} is dependent on the existence of the IF-MATCH header? That feels a little tricky to me , as a common problem for newbies will be to forget toadd If-Match when trying to to a ‘normal’ PUT on an existing composition. [/quote] Yes, the missing If-Match header implies a the client requests to create a resource, while the presence implies that the client requests to update a resource (the one identified by versioned_object_uid from the url, while the header is just a check for the version validity). So when a someone wants to update a resource, and forgets to add the header (and assuming that a previous version already exist on the sever), it will get a http-error (we have to see if it would be 412, 409 or 400). The meaning of the PUT operation (create vs update) is changing dependent on client assumptions (which will have to be set in the headers). But the meaning of the {uid_based_id} is always the same: a `versioned_object_uid` for identifying a VERSIONED_OBJECT in a form of a HIER_OBJECT_ID. For the PUT with a contribution (which is not yet part of the specs): it could be used to create a contribution with a client-generated uid, the rest should be working the same as POST. In case the contribution with that uid already exist, or one of the version could not be committed, it should return a 409 (or something else). --- ## Post #41 by @sebastian.iancu [quote="stefanspiska, post:30, topic:2113"] The composition uid is just the [Common Information Model](https://specifications.openehr.org/releases/RM/latest/common.html#_locatable_class) locatable uid. so Its a bit strange that one is special and needs a specific syntax. [/quote] We should always use the `versioned_object_uid` value for the `uid_based_id` parameter in the PUT https://{baseUrl}/v1/ehr/{ehr_id}/composition/{uid_based_id}. Do you see a problem with this? For contribution, in the version you should be able to add two versions (one of the composition, another of a folder with a reference to that composition), both containing a client-generated uid . I see now that the example on the spec is using OBJECT_VERSION_ID (including the version number), but I guess it could be also HIER_OBJECT_ID. So the client has options but also responsibilities, because there are no other checks or pre-condition header, so the operation should be atomic (all or nothing). Why would you think this would not work? What problem or issue do you see here? --- ## Post #42 by @pablo [quote="ian.mcnicoll, post:17, topic:2113"] The context is bulk transfer of contents of one CDR to another, preferably using standard REST API calls [/quote] In EHRServer and Atomik we have such bulk transfers but are not done via standard REST API calls since current API doesn't support that. We call that `sync` API. Our `sync` API copies everything to another server that supports the API, so each CDR instance could be client or server for other CDR instance, it works in a master/slave (or primary/secondary to be politically correct) way, the master is actually the data source and the secondary the destination of the data. In "everything" I mean: - opts - ehrs - queries - users / organizations (if the internal identity provider is used) - contributions - versioned objects - versions - compositions - ... And now that we support demographics in Atomik, we will also sync Actors, Roles, Identities, Contacts, Relationships, etc. But all this needs another API. --- ## Post #43 by @stefanspiska If I can via a POST contribution provide a composition with change type creation with a set composition .uid then It makes no sense to me way I should not be able to POST a composition with a set composition .uid and the Serve should respect that. --- ## Post #44 by @sebastian.iancu One reason is that Contribution is a lower level functionality comparative to 'normal' resources like Composition, Ehr, or Folder. A Contribution is also an operation in itself (an action, the equivalent of db-transaction that the client want to be executed), and as a result of that operation the Ehr gets the 'trail' as the Contribution resource. So it makes sense to me that the contribution endpoint might be loaded with more non-standard Rest functionality, while we try to keep the other 'normal' resource endpoint as 'standard' as possible (POST to create using server-side identification assignment, PUT with client-side, or update). Another potential reason for PUT with uid is that it might be easier to check first all the precondition to engage in executing the operation without parsing/unserialiazing the payload-content. If instead you'll use POST and uid is in the payload, then you will need to consume that content first, then extract the uid, then you can assess preconditions. Another reason would be the alignment with the way FHIR defined their http specifications. But in any case this is still a proposal, it can still be done differently (e.g. rather POST then PUT), if there is sufficient feedback from implementations. In any case, we should keep consistency across operations: use always PUT with the id, not only for composition, but also for Ehr, templates, queries, etc. - or use always POST and with the id in the payload. --- ## Post #45 by @sebastian.iancu This sync API you made would be interesting perhaps also for others - do you intend to propose for openEHR specs? This is of course worth another discourse topic ... --- ## Post #46 by @vidi42 My 2 cents on using PUT vs POST for predefining the composition ID. It makes sense to use the PUT when you want to store a named object (even for creation) and to use POST when you let the server decide how to name the object. However, the current API definition mentions the PUT to be used for updates. Besides that, by allowing setting the composition ID through POST, but not enforcing it, means the server can still decide how to store the composition object, so it's not necessarily a violation of the POST definition. On EHRbase side, to move forward until a new definition of the EHR REST API is released that properly defines how PUT should be used for creation, we are considering to go with respecting the composition ID in POST if it's present. --- ## Post #47 by @thomas.beale [quote="pablo, post:42, topic:2113"] But all this needs another API [/quote] [Here is a placeholder](https://specifications.openehr.org/releases/SM/latest/openehr_platform.html#_admin_service). Without trying to get into the PUT/POST debate I would say one thing: REST and HTTP protocol have no built-in notion of versioning. Any architecture that does, and wants to expose CRUD calls via REST needs to decide if a 'resource' is a versioned thing, or one version of a versioning thing, and from there use POST and PUT consistently within that architecture, without worrying too much if it's not identical to other architectures. [quote="vidi42, post:46, topic:2113"] It makes sense to use the PUT when you want to store a named object (even for creation) and to use POST when you let the server decide how to name the object. [/quote] This I believe is the standard REST thinking. --- ## Post #48 by @Simon We've now got compositions being imported using the POST composition using an existing composition id. We start with the old version POST and then once created we PUT any later versions, all in order. We're currently testing it but it seems like a good start. Next steps are to use the Contribution API, shall I do this on a new thread? I'm also worried that we get too much into a REST debate (its not even a standard). I once got told off by Roy Fielding, and I don't want to go back there. I must admit I've learnt more about openEHR in the last few weeks than ever before ;) The bulk export and import of compositions(with versions) is an important part of the standard. New thread required ? --- ## Post #49 by @ian.mcnicoll Excellent - practical progress and learning. With a bit more thought, it seems to me that deciding on this at single composition level is a bit of a distraction, as most use -cases for client-generated composition uids will actually involve working at Contribution level. That does raise some more questions but might actually be easier to resolve - if nothing else the data representations in the contribution body at that level are closer to pure RM and we will be less tangled up with 'RESTful' debates I vote for a new thread on 'replaying Contributions' --- ## Post #50 by @sebastian.iancu Thanks your your input Alex. But to be a bit clear for the scope of this comments above - it was more a discussion about what & how should we change specifications, which eventually should be followed by implementation - but in any case, this does not necessary have to be supported yet by EhrBase. --- ## Post #51 by @pablo I didn't know that could be of interest, of course I can propose it to the SEC. --- ## Post #52 by @birger.haarbrandt Hey all, it is Birger coming in with a naive and maybe stupid question: my understanding is that even a POST of a composition is actually something like an "implicit contribution" with only a single versioned object inside of change type create. Hence, we might also consider it as kind of an abbreviation for lazy people. Hence, I don't understand why we should start treating them differently (Sebastian referred to contributions as "lower level functionality "). From the point of EHRbase, I favor the approach that @vidi42 suggested. --- ## Post #53 by @pablo [quote="thomas.beale, post:47, topic:2113"] [quote="pablo, post:42, topic:2113"] But all this needs another API [/quote] [Here is a placeholder ](https://specifications.openehr.org/releases/SM/latest/openehr_platform.html#_admin_service). [/quote] @thomas.beale from what I understand from that interface I_ADMIN_SERVICE in the SM is that is a pull kind of service (list_contributions). What I described above that we have a `Sync API` in EHRServer and Atomik is a push service: the server instance that has the data pushes the data to the other servers in the cluster, so the semantics of the `Sync API` are like create_ehr, create_contribution, create_composition, create_query, create_template and so on. --- **Canonical:** https://discourse.openehr.org/t/rest-api-for-creating-compositions-with-id/2113 **Original content:** https://discourse.openehr.org/t/rest-api-for-creating-compositions-with-id/2113