Atomik CDR and DDR website is online and demographic API proposal

Hi all, lately I’ve been working on releasing Atomik, a new website and docs. Finally the new Atomik website is online https://atomik.app

Please let me know what you think about the site and what would you like to see there. Note I’m still working on the docs, but will be completed soon.

One thing I added to Atomik, that wasn’t in it’s open source sibling EHRServer, is support for the demographic model. To support this I needed to design a REST API for the demographic model to commit and retrieve those resources. This is what I have so far (I’ll make a more formal documentation in OpenAPI and propose it for review to the SEC ASAP):

POST /demographic/actor
Creates any type of ACTOR (PERSON, ORGANISATION, GROUP, AGENT) from a non empty payload.

Design note: I have considered ROLE as a weak entity and should always be inside an ACTOR when you need to create an instance. So this endpoint also creates the ROLEs if any is provided. I also consider CONTACT and PARTY_IDENTITY to be weak entities, so they will always be created when the container ACTOR is created.

PUT /demographic/actor/$versioned_uid
Modifies an existing ACTOR. Needs an If-Match header with the version.uid of the current last version of the versioned object, which UID comes in the URL as $versioned_uid.

GET /demographic/actor/version_uid
Retrieves an ACTOR by version UID.

POST /demographic/relationship
Creates a PARTY_RELATIONSHIP between two existing ACTORs. The server should check both source and target references exist.

PUT /demographic/relationship/$versioned_uid
Modifies an existing PARTY_RELATIONSHIP. Needs an If-Match header with the version.uid of the current last version of the versioned object, which UID comes in the URL as $versioned_uid.

GET /demographic/relationship/version_uid
Retrieves the PARTY_RELATIONSHIP by version UID.

I didn’t implement the get xxx at time, but follows the same logical design.

Design note: you can see both ACTOR and PARTY_RELATIONSHIP are strong entities (top-level versionable), the rest just depend on ACTOR.

3 Likes

@pablo Thanks, and great job. Interestingly PARTY_RELATIONSHIP is not considered a weak entity :slight_smile:

1 Like

Thanks @chunlan.ma the reason for that is that if relationships would be “weak”, then the relationships would need to be created when, for instance, a person is created, like what I described for the roles. I think having the relationships to be created individually from the other entities they point to, adds flexibility.

Though it could be accepted that you create person1 then create person2, with a relationship embedded, that points to person1 in it’s target (I preferred not to do it that way). Then if the system supports reverse_relationships, the system needs to set the relationship inside person1. In terms of resource management, I think modifying a resource because another resource reference them, is not a good. I prefer each endpoint to modify the resource for that endpoint, that is also why PARTY_RELATIONSHIP is in it’s own endpoint, when that is created or modified, the PARTIES it points to are not modified at all, not even for the relationships. So in the API and internally both are independent (PARTY and PARTY_RELATIONSHIP).

Another point is to make the demographic model as tree-like as we could, that simplifies modeling, API and storage handling. The problem is with ACTOR.roles / ROLE.performer, and PARTY_RELATIONSHIP.source/target and PARTY.relationships/reverse_relationships, when you look at the data you really have a complex graph, not a tree like in a COMPOSITION structure. REF Demographic Information Model

Having graphs is more difficult for managing data and for querying data, than having just trees.

Very nice!

Regarding URI pattern for then not-yet-exixting REST APIs, I believe we in the sec discussed that a more future proof way of dealing with upcoming extensions of “demographic” would be to call the path “registry” when creating a new API.

If we apply this already now (when creating the new REST API) then it may of course temporarily be a bit confusing until the “demographic” package is subsumed by a broader “registry” package. The upside would be not having to change the URI paths later.

Any thoughts about this?

1 Like

@erik.sundvall I think it’s better to be consistent with current packages when naming REST API endpoints.

Later, if the RM adds support for a registry or entity package, we can release a new API spec for that one, and because eve with that RM added, the current demographic will still be valid, the demographic API will also be valid. Then if we deprecate the demographic model, we can do the same with the API, and lastly the only living spec, RM and API, will be registry/entity, but we have a long way to go to reach that moment.

For now I would like to focus on giving some API level access for the current demographic spec.

Also consider we have to line up after Thomas departure from managing the specs, which will be a painful handover to the rest of the SEC.

@pablo Thanks Pablo for the explanations, which make sense. When it is not a weak entity, it means this is versioned and can be queried individually. I was thinking more about the scenarios when we need to use PARTY_RELATIONSHIP instances independently. Your current implementation adds more flexibility in changing, querying, and reporting PARTY_RELATIONSHIPS, but it may require more service requests when the user wants to always retrieve the source party along with the relationships. Anyway, just a thought. I agree ROLE is a weak entity.

Great job!!!

1 Like

My explanation was a tongue twister but your interpretation is exactly on point. Is that plus it has it’s own API level resource that is independently handled from other top-level/strong entities.

Exactly, I think of it as PARTY_RELATIONSHIP is a join table in a relational database model, basically has pointers to other entities in other “tables”, though in openEHR the relationship can hold data itself besides having the pointers. These join tables are common implementation for many-to-many relationships, and PARTY_RELATIONSHIP fits that definition at a conceptual model level.

You are right again, though we can think of endpoints that allow to return relationships too, but for the initial spec + reference implementation I would like to try the independent endpoints for relationship and actor, so we can test their limitations. Maybe we figure out that is a good approach, or maybe we detect that is not enough. I think having something working that we can try out will help as input for the discussion.

Yes, that suits the definition of “weak” you posted, though internally in the CDR it is just like any other LOCATABLE, like FOLDERs in EHR.directory, it won’t be individually versioned, it’s versioned only inside it’s container, which will be an ACTOR. Though in the case of FOLDER is not that FOLDER is a weak, is just that the top FOLDER is the “strong” then all descendants are “weak” (I guess weak/strong are abused terms but are useful for explaining the idea, we should come up with better terminology though).

Thanks @pablo, good initiative and exploration of a potential API for demographics.

While I don’t want to directly discourage you, and neither criticize the API without presenting alternatives, I still must say that this is (at this time) Atomik.app variant of the API for demographics. As @erik.sundvall mentioned, there were already discussions going on about the openEHR API for demographics within the SEC, results being summarized here.
There were also numerous discussions in SEC, occasions and topics on discourse over the last X years where I showed and explained Code24 experience with such API, which I’m hoping will be also taken in considerations in the official openEHR API specs.

Besides the naming in the url issue, i.e. demographic vs registry (see also Demographic model improvements), I see a few other issues to be tackled:

  • missing the contribution endpoint (although in your design I think everything is still versioned)
  • the PARTY_RELATIONSHIP should not be that weak on the ‘source’ side - i.e. every time a PARTY gets a change in their direct-relationship list it should end up in a new version; we discussed the SEC that reverse_relationship should become a function instead of an attribute, so that it can be computed/calculated instead of persisted
  • PARTY_RELATIONSHIP should not be versioned (but is a LOCATABLE); we should have anyways an endpoint to GET them, but the creation/update is always in relation with their source
  • ROLE should not be weak, should be versioned and also needs to be supported by the API at a separate endpoint
  • an ACTOR contains a reference to a ROLE (via PARTY_REF), but not the ROLE itself so we should not make it part of the ACTOR REST resource
  • an ACTOR is an abstract type, I suggested in SEC to have API endpoints for concrete types (PERSON, GROUP, etc)
  • you mentioned RM 1.0.3 specs, but I think we discussed in SEC that we should focus on a REST spec for RM 1.1
  • we’ll need a SYSTEM concept also
  • we’ll also need support in AQL and on /query endpoint
1 Like

If we don’t have a formal API it’s difficult that this is an alternative :slight_smile:

The point of all this is to start defining things, and I’m using Atomik just as a reference implementation to test things out, to check what works and doesn’t, where difficulties could be, etc. with one key point: I want to use the current demographics model.

So we have two discussions or problems to solve:

  1. current published demographic spec doesn’t have an API

  2. demographic model could be improved, and maybe superseded by another spec

MY goal is 1. which is something that could happen in the short term. For 2. we still a long way to go defining RM model changes, needing to deprecate current model, etc. and all that in the middle of Thomas leaving the spec maintenance processes, for which we need a handover of his processes into the SEC. I would say it’s not the right time for 2.

1 Like

BTW @sebastian.iancu that is an isolated problem, because we need to focus on querying demographics before designing an API for that, which I think would be trivial, the real issue is thinking about AQL for demographics. In my case, I already integrated querying of demographics in SAQM (our openEHR query formalism), and I’m currently testing how SNOMED CT relationship concepts can be used in PARTY_RELATIONSHIP to query related ACTORs.

About querying demographics in Atomik, and this might not be standardized for a while in AQL but I think there are ideas that can be migrated:

Atomik can query for relationships between demographic entities based on the type of relationship, and test queries live from our Query Builder. Even mixing SNOMED CT expression for semantic filtering. This is the full screen for a query design in Atomik which follows the SAQM (Simple Archetype Query Model formalism, which is compatible with a subset of AQL but it’s focused on the model model not on the query syntax).

Soon we will be able to query full family trees and link their EHRs too, opening the door for multiple secondary uses like reporting inherited chronic disease risks.

The one design change I think you should consider from the Entity model is to add the ACCOUNTABLITY class and its relationships.

Accountability handles a problem in the existing Demographic model, which is the inability to properly represent both a ‘Role’ as a kind of professional persona (Joan Smith is a GP even when she is not working, because she remains licensed by the medical board) and a job post, which is an accountability of Party A to Party B (e.g. Joan Smith works for the Chiswick NHS Primary Care trust).

ROLEs in the Demographic model are shown as PERSONA in the Entity model, but don’t worry about that.

The important thing is that you can’t adequately represent an individual’s capabilities (Personas / Roles) AND an organisation’s available posts (if you wanted to do that) AND filled job posts, i.e. who is working as what for whom.

For this reason, I would advocate for making this one change (adding ACCOUNTABILITY) to the current Demographic model.

I agree with most of your design considerations.

Hi @thomas.beale I see the current ROLE mixes both concepts: what an actor does based on an actual participation vs. what an actor could do based on it’s credentials.

In general I prefer to use ROLE for to record the “hat” an actor has at the moment of participating of some process, so what they do based on actual participation.

Then the CREDENTIAL is an orthogonal concept to ROLE in the way I like to use it, which is associated with the ACTOR in an absolute way, e.g. if you are a GP you have that credential independently of any ROLEs or RELATIONSHIPs you have.

An interesting thing is, some RELATIONSHIPs might require a CREDENTIAL, so the RELATIONSHIP could depend on the CREDENTIAL but not viceversa. For instance, a PERSON has CREDENTIAL=GP and a RELATIONSHIP to an ORGANISATION, and the RELATIONSHIP type “works_for” requires a CREDENTIAL=GP, which is kind of a rule, not part of the RM itself. Maybe we could use the expression language to express such rules/requirements based on the demographic model. This needs more analysis :slight_smile:

Yes this is true. Currently the Entity model doesn’t include a list of credentials for ACCOUNTABILITY. It probably should.