Assessment Configuration API
The configuration information for a client to run an assessment is described through an assessment configuration. This is an arbitrary JSON graph, with some server support for customizing the graph and validating the graph through examination and transformation of the Jackson object model for the JSON itself.
Assessment configurations exist in a one-to-one relationship with assessment revisions. They are retrieved through the assessments API, and they can be retrieved separately from the assessment metadata.
Assessment configurations are deleted when their associated assessment revision is deleted. Like other Bridge resources, when the assessment revision is logically deleted, both the assessment and the configuration will continue to be available through the API if they are referenced directly.
Shared assessment configurations cannot be modified. If an assessment is imported from a shared assessment, and then its configuration is modified, this is allowed, but the assessment no longer reports that it is an instance of the shared assessment (we cannot guarantee that it is still a validated instance of that assessment). Instead, there is an API that allows a shared assessment author to define customizations that can be made to the configuration through a separate endpoint.
API
A minimal root node (“{}”) configuration is created when you create an assessment. The JSON that can be stored for this configuration is arbitrary, but it should follow a couple of rules:
Each object node in the tree should have an
identifier
property that uniquely identifies that node in the entire configuration tree;Each object node in the tree should have a
type
property that distinguishes the type of the node in the configuration tree.
These values are needed to implement customization and validation support on the server.
METHOD | URL | Perms | Description |
---|---|---|---|
GET | /v1/assessments/{guid}/config | Dev, User | Returns an assessment configuration. Consented users can use this API to retrieve the configuration for an assessment that is scheduled to them, without having to retrieve the full assessment record. |
POST | /v1/assessments/{guid}/config | Dev | Update an assessment configuration. Any link to a shared assessment is removed. |
GET | /v1/sharedassessments/{guid}/config | Dev | Get the configuration of a shared assessment (it cannot be changed). |
In the Assessment
object, there is a customizationFields
property that specifies the segments of this configuration tree that can be changed without invalidating the assessment as a copy of a shared assessment. The field has this value: Map<String, Set<PropertyInfo>>
. This is a map from node identifier
fields to a set of PropertyInfo
objects that describe the properties on that node that can be changed. The PropertyInfo
object contains enough information to create a customization UI, to collect changes from a study designer:
PropertyInfo {
// the property name in the JSON
String propName;
// a human readable label for this field
String label;
// a description to a human editor as to what is allowable in this
// field, e.g. "This field must include a number from 1-5."
String description;
// type of data being collected. Not constrained for complex cases,
// but we suggest 'string', 'number' and 'boolean' to start
String type;
}
An update to the customization API takes the form: Map<String, Map<String, JsonNode>>
, again mapping the identifier of a node to the properties to be changed on that node, with the property names being the keys to arbitrary JsonNode values (these can be anything, but the PropertyInfo object may indicate constraints based on editor support):
METHOD | URL | Perms | Description |
---|---|---|---|
POST | /v1/assessments/{guid}/customize | Developer, Study Designer | A special JSON format that describes the fields to update, that must match what is allowed in the assessment module definition. Only updates the indicated fields, and does not remove a link to the shared module. |
Java Classes
@Entity
@Table(name = "AssessmentConfigs")
public class AssessmentConfig {
// Assessment configuration has the same guid as its assessment revision
@Id
private String guid;
// At 65k this field should be large enough
@Convert(converter = JsonNodeAttributeConverter.class)
private JsonNode json;
@Convert(converter = DateTimeToLongAttributeConverter.class)
private DateTime createdOn;
@Convert(converter = DateTimeToLongAttributeConverter.class)
private DateTime modifiedOn;
@Version
private long version;
... getters and setters ommitted
}
Assessment Services
The service is a simple service supporting CRUD operations, there is no publishing, versioning, etc.
public interface AssessmentService {
/**
* Returns any assessment configuration and all its children.
*/
public AssessmentConfig getAssessmentConfig(String appId, String guid);
/**
* Persist an assessment configuration.
*/
public AssessmentConfig updateAssessmentConfig(String appId,
String guid, AssessmentConfig config);
/**
* Make select changes to the config while maintaining it as a valid
* copy of a shared assessment. The customizations map a JsonObject
* identifier (like a guid) to a map of field changes on that object,
* keyed from property to the change that should be made to that
* property (the JsonNode). The assessment's configuration mapping
* is walked to make these changes, so any entries that are not allowed
* by that mapping will be ignored.
*/
public AssessmentConfig customizeAssessmentConfig(String appId,
String guid, Map<String, Map<String, JsonNode>> customizations);
/**
* Physically delete this configuration if the assessment revision it is
* associated to is being deleted.
*/
public void deleteAssessmentConfigPermanently(String appId,
String guid);
}
SQL Schema
Assessment validation (optional)
At a later time we can validate a configuration by walking the node tree and applying validation rules based on the type
property of each node. This would be implemented using the same validators and InvalidEntityException
system we use for other model objects in the Bridge System. We would pair a tree traversal algorithm with a validator implementation that validated the JSON based on the nodes and their types.
Validation can enforce:
the cardinality and type of children that a node type can accept;
that certain required properties are present; and
that properties have valid values.
Migration and impact considerations
(For a fuller discussion, see here.) Assessments and their configuration are entirely separate from existing code and will not be available to the existing scheduling system, so they will have no impact on “Bridge 1.”
This design associates assessments with studies. Although the app context boundary is no longer strictly a study boundary, the studyId
as a tenant identifier is so embedded in our application we’re unlikely to remove it in our implementation. However, assessments are globally available to all protocols in an app, so this association is correct and will not have to be changed later when protocols are introduced. (Alternatively we can bite the bullet and start calling this appId
for these new tables)