What is the '#visits' for at the end of the URL in 'Recent Visits' widget ?

Hi everyone,

I’ve noticed that when I click on a link to a recent visit, from the Clinician Facing dashboard (‘Recent Visits’ widget), I am redirected to:


I can see that #visits is set in different places in the code but in this case, here:

What is this #visits for ?

and also why do we use patient.uuid instead of patient.patientId ?

I’m guessing the #visits at the end of the URL aims to activate the visits tab on the page.

We use patient.uuid instead of patient.patientId because, in most cases, we’re fetching data about the patient through web services. The patient.patientId attribute (like all id attributes on OpenMRS tables) represents an internal identifier for the table. Internal identifiers are used for internal consistency, but should not be exposed externally (including through web services). Many implementations have OpenMRS running on multiple servers. Internal identifiers can vary between servers. So, technically speaking, an internal ID could be used in this case (for a web page), but using UUIDs is more robust and, because we are using web services in many places of the web app, the best practice to identify resources.

Hope that helps. A dev could probably give a better answer on the #visits URL question.


-Burke :burke:

Hi @burke , so this design choice was made having in mind that patients would be shared across several OpenMRS instances? That’s not anymore just metadata sharing, but would rather imply data syncing between instances, is there such a module out there?

Yes. There is a sync module, but it’s very complicated and once installed cannot be removed. The PIH group created it and it has been used by a handful of other implementations. I know, for example, FACES was using it in Kisumu, Kenya. But it’s a non-trivial module to adopt, manage, and maintain. From what I’ve heard, the challenges are mostly in setup/configuration, followed by stretches of tranquil bliss, and occasionally interrupted with issues that often require experienced devs to resolve.

Most implementations that grow to cover more than a single building eventually find themselves expanding to multiple servers. I believe PIH has dozens or more servers for several of their projects and AMPATH has nearly a hundred sites with dozens of servers. AMPATH has been using a remote formentry module that was meant as a short-term workaround to lack of sync and has it’s own drawbacks. The ultimate architecture would be an HIE (or mini-HIE), but I don’t know of examples of any group doing this yet. In general, I think larger implementations end up finding some way to consolidate data, using sync, remote formentry, or some other homespun approach to the problem to bring data to a central server and, as best as possible, address & resolve duplicate records in the process. It’s messy. As our clinical informatics mentor, Dr. Clem McDonald, taught us: “Life is hard.” :wink:

In any case, sharing internal keys externally is a bad practice that will usually come back to haunt you. We’ve fallen too far down this path with concept IDs (since internal integers are much easier for humans to handle than UUIDs) and are trying to avoid making similar mistakes going forward. Ultimately, I’d like to see even our concept IDs (currently primary keys) be converted to a concept.key or concept.code designed specifically for human consumption and evolving as something distinct from the internal primary key in the database.

This conversation about synchronizing data across servers is a bit of a tangent for your original question. The reason that code uses patient.uuid instead of patient.id is:

  • we are moving towards using REST web services more and more, and REST does not expose the internal pk, but only the uuid. E.g. the find patient page uses REST and thus ends up sending you to the patient dashboard using the uuid.
  • we want to support having some apps be written as server-side code, and others as client-side code, therefore we try to use URL templates that can be evaluated against a context that contains REST representations of our data. (In this specific case it’s only halfway implemented that way, e.g. it also has visit.id, but that’s the general idea.

Thanks @darius, this makes a lot of sense indeed. And thanks @burke for bringing your insight about existing implementations… etc.