In an earlier blog post, we wrote that some of Indicium Universal's APIs were more complicated than their counterparts in the ‘regular’ version of Indicium. It was hinted at that the reason for this difference was related to security improvements and that we were looking into ways to simplify them. This is important to us because we want everyone to use Indicium Universal as much as possible due to its improved security and it would be a shame if its more complicated APIs would be a deterrent.
As of version 2020.1.1 of Indicium Universal, we have combined the best of both worlds; simple and secure APIs. The APIs of Indicium Universal are now as simple as they used to be without giving up on any security or data integrity checks. In this blog we want to give more background information on why we needed to complicate the APIs in the first place and how we managed to simplify them again. In doing so, we want to shed more light on what Indicium does behind the scenes, which challenges we face during development and how we solve them. At the end of this blog we will recap which version of Indicium is most suited for you after these changes.
Before splitting Indicium up into two products, we faced some challenges that made it impossible for Indicium to enforce the full scope of input validations without breaking valid scenarios as well. Some of these problematic input validations include lookups with prefilters or values in hidden fields. For instance, a user should not be able to select a lookup value outside of their locked prefilters. At the same time however, a user can save a record with lookup values that they can't select, as long as the user was not the one to enter the value.
Example using TCP
To clarify the problem, let's look at a specific example using the reporting of issues in TCP. When talking about issues in TCP, there are three roles to consider. One person reports the issue, another person validates the issue and assigns it to a department and another person solves the issue and assigns it to a product version. These three people work on the same record but have different permissions. In particular, the person who reports the issue is unable to see most of the fields that are present in the record.
So now let's consider the situation where the issue has already been validated and assigned to a department, but the person who reported the issue wants to update the description. When that person clicks save, they send the entire record to Indicium, including values for columns they can't see or are not allowed to select. The validity of this request depends on the question who entered those values. Indicium could compare the new record to the old record, but things get more complicated when hidden columns are filled out by means of a default procedure.
In many cases like these, Indicium is unable to feasibly determine how the values in the record came to be and therefore cannot validate it. If we are too strict, then the user cannot update the description of their issue. If we are too lenient, then the user can directly assign their own issue to a department.
When considering the example above, the core problem is that the state of the record is being tracked by the GUI and that the record is not sent to Indicium until the save action is performed. Furthermore, establishing the records client-side means that the GUI is also responsible for calling and processing application logic. Ideally, all of these things would be the responsibility of the server. This keeps the GUI simple, but more importantly, it ensures that application logic cannot be skipped, removes the need for the GUI to know about values that should be hidden to the user and allows Indicium to validate all user input. To overcome these shortcomings, Indicium Universal introduces a feature that we call ‘resource staging’.
Enter resource staging
Resource staging is the mechanism through which Indicium controls the state of a record or a set of parameters while it is being edited by a user. Every insert, update, task and report action is represented by a resource. Every change made by a user in a GUI is performed by a request to Indicium's API to change the state of the resource. Every change that is made to a resource by means of application logic, however, is done automatically by Indicium whenever necessary. This creates a very clear separation between the values that are entered by the user and the values that are entered by the ‘system’. This in turn allows us to validate user input without breaking valid scenarios. Each time the state of the resource is changed, Indicium will, if necessary, call the layout and default procedures and refresh expressions. This way the client can simply push a value change to the server and fetch the new state of the record, simple and secure.
So what does this mean? To answer that, let's take a look at the old situation first. The image below roughly sketches how a GUI would communicate with the ‘old’ Indicium when adding a record. As shown by the image, the GUI keeps track of the state of the record in memory. It is also the GUI's responsibility to call the application logic procedures, apply their results to the record and ensure that the user can only enter values into editable fields. When the record is saved, the GUI sends the entire record, which contains both user input and application logic input, to Indicium in a single request. The mixed nature of the record makes it impossible for Indicium to validate the values of the record in a feasible way. Indicium also cannot know if the GUI even performed the application logic requests and applied them properly. Someone could just send the final request to Indicium with a record that they have forged manually.
Now let's have a look at the new situation with Indicium Universal. When the user indicates that they want to add a record, the GUI will request Indicium Universal to create a new resource to represent that record. Indicium Universal will apply all default and context values, as well as default and layout logic right away. The GUI will then fetch the initialized resource and update its UI with the values and layout state. As the image shows, the only changes made to the resource through API requests are the changes that the user makes in the GUI. Indicium Universal validates these requests heavily by checking if the property is editable and if lookup values are within the user's lookup set, etc. When the record needs to be saved, a request will be made to Indicium to commit the resource that represents the record.
Resource staging is a great mechanism that allows the GUI to be very simple because it doesn't need to know anything about application logic, it simply pushes values to Indicium Universal and retrieves the new state of the record. Furthermore, this greatly increases security by making it impossible to bypass any type of application logic or permissions. With that said, the API for third party clients is more complicated this way. The record in the example above could be saved in a single request with the old Indicium while it requires four requests with Indicium Universal. This brings us back to the point of the APIs of Indicium Universal being more complicated, a problem which has now been resolved as of version 2020.1.1.
Simplifying the APIs
In version 2020.1.1 of Indicium we have re-enabled the single request APIs and built their implementations on top of resource staging. Clients can send all column/parameter values in a single request and Indicium will go through the process of resource staging and stage the values in the order that they’re supplied in. This does mean that the client should only include the values that are entered by the user and that the order of the properties in the request body is important.
So what does this mean for you?
Simply put, this means that Indicium Universal should be your default choice of Indicium and you should only choose the old Indicium when you are using a Windows GUI or Mobile GUI. Note that it is also possible to run them side-by-side on the same IAM database.
We are currently looking into the option to make the Windows GUI work on Indicium Universal as well, instead of the old Indicium, in order to utilize the mentioned advantages and increase the adoption of Indicium Universal. In the end it is our goal to phase out the old version of Indicium entirely after it has served its purpose of bridging the gap until the Universal GUI is ready.