Rest API for generic tagging

If the module id is openmrs-module-tag, does it mean the artifact id is tag?

Yes, it would be the “tag” module.

While working on this method we came across an issue, regarding privileges. Since this method is returning OpenmrsObject, the user will be able to view all the different types of objects. However there might be cases where a User has the privilege to view Concepts, but not Locations. This method does not take the individual privileges into consideration. One way around would be to add a new privilege View Objects which lets a user to view all the objects.

What @darius has suggested would have been the correct approach if we were using String tags. However we are using Tag objects, and hence we will have to use a different approach since every Tag object has its own metadata.

Just to add to what @jtatia is saying, a method like TagService.getTaggedObject(String tag, Class c) should require some sort of elevated privilege that allows one to view virtually any object, it would be a privilege in the module.

As for the rest API, if we implemented something like .../v1/tag/my-favorites to return {"tag": "my-favorites", "usageCount": 5,...} then the return value ceases to be a tag resource, conventionally my-favorites in the URL is a unique identifier for a single resource, plus we would also want to include the metadata for each tag resource which wouldn’t be possible with this design since each ‘tag’ really would seem like a grouping rather than an individual resource. One workaround to achieve Darius’ suggestion would be to introduce other composite resources that encapsulate these other details that we want to support e.g TaggedObject and TagUsage resources otherwise we have to assume it will be up to the rest client to deal with processing the returned tag resources in order to build these compositions. Possibly, for those using angular, we could add an angular service that has convenience functions that do this processing that way we take the burden away from the client.

hey @burke , @darius what do you think ? :grinning:

Jai and I are also considering writing a fragment for the new UI and possibly an angular directive that one can include on a form for an OpenmrsObject that allows a user to view/add/remove tags. They would take in the following arguments:

viewOnly (boolean): Specifies if the user can only view or can view and also add/remove tags uuid (String): The uuid of the OpenmrsObject type (String): The fully qualified java class name of the domain object

Introducing a new privilege does not make sense here.

Every user should be allowed to see tags on things that they have access to, but we should not allow users to see all objects just so that they can see tags.

I don’t have any constructive suggestions for how to approach this right now. (I just want to send this message quickly so I reply with something, rather than nothing
 :slight_smile: )

I suggest that the way to think about this is to ask “what does a consumer of this REST API want to get?” My suggestion here is based on what I guess the consumer wants. E.g. the only useful thing about an existing tag is how often it’s used.

I thought that @burke and I proposed that tags should not have any additional metadata besides the name. There may be a tag table for performance purposes, but even if we do that, the API shouldn’t need to expose this to the consumer.

What is the metadata that a Tag object will have?

Again, you’ll have to explain what metadata we have for a tag resource, and why it’s important.

Also, what’s wrong with exposing a generated field like “usageCount” in a resource representation?

Quick thought (just a slight preference) would be that instead of “viewOnly” it should be “editable” (and default to false)

Tag object contains data regarding a tag added to an OpenmrsObject, i.e. which “tag” is placed on which Openmrs object, by whom (user) and the data when it was added. Its like u mentioned, for performance purposes, we can use a single table to get information regarding which object has which tags.

making a get request like this :

(in actual the url will be a bit different : GET 
/tag?q=my-favorites) will return a list of tag Objects having this phrase in the tag i.e.

{ "uuid": uuid-of-tag-object "tag": "my-favorites", "objectType": "patient", "objectUuid": ".../patient/uuid-of-tagged-patient", "auditInfo": info regarding creator and dateCreated }, { "uuid": uuid-of-tag-object "tag": "my-favorites-of-all", "objectType": "concept", "objectUuid": ".../patient/uuid-of-tagged-concept", "auditInfo": info regarding creator and dateCreated }

Darius and I had a discussion around this on the Wednesday design call and below is what we suggest to be implemented:

GET .../v1/tag/my-favorites

{
"tag": "my-favorites",
"links": [
        {"rel": "patient", "uri": ".../patient/uuid-of-tagged-patient"},
        {"rel": "concept", "uri": ".../patient/uuid-of-tagged-concept"}
        //....
    ]
}

GET .../v1/tag/my-favorites?v=full

[
  {
    "uuid": "uuid-of-tag-object",
    "tag": "my-favorites",
    "objectType": "patient",
    "objectUuid": ".../patient/uuid-of-tagged-patient",
    "auditInfo": ""
  },
  {
    "uuid": "uuid-of-tag-object",
    "tag": "my-favorites-of-all",
    "objectType": "concept",
    "objectUuid": ".../patient/uuid-of-tagged-concept",
    "auditInfo": ""
  }
]

We shouldn’t add the TagService.getTaggedObject(String uuid, Class type) method exposed on the public API.

Instead of adding the fragment or angular component, we will first implement tagging of patients from the clinician facing patient dashboard in the ref app, this will help us write the rest API based on a concrete use case.

1 Like