Form Instrument
Structure
An Open Data Capture form instrument (i.e., the object that is the default export from the index source file) consists of several properties that together define the data and display model. By convention, these properties should be sorted in the order in which they are documented below (e.g., kind
should be the first property, followed by language
).
kind
- The discriminator key for the type of instrument (e.g., form). This is primarily used to determine the structure of the content.
language
- The language(s) in which the instrument is written. If the instrument is available in only one language, this should be a string (e.g.,
'en'
). On the other hand, if the instrument is available in multiple languages, this should be an array of languages (e.g.,['en', 'fr']
).
- The language(s) in which the instrument is written. If the instrument is available in only one language, this should be a string (e.g.,
internal
- Information about the instrument that is used internally to generate a unique identifier. As such, the combination of
name
andedition
should not conflict with any existing instruments in the database.
- Information about the instrument that is used internally to generate a unique identifier. As such, the combination of
internal.name
- The full English name of the instrument in screaming snake case (e.g.,
'HAPPINESS_QUESTIONNAIRE'
).
- The full English name of the instrument in screaming snake case (e.g.,
internal.edition
- A positive integer indicating the internal version of the implementation of this instrument. For a given instrument implementation, this should initially be set to 1 and incremented on each subsequent iteration. For example, suppose the “Happiness Questionnaire Version 1” is initially implemented (as edition 1) in the platform. However, edition 1 has a poor validation schema, so edition 2 is an internal revision to fix the validation schema. If “Happiness Questionnaire Version 2” is published, it can then be implemented in the platform as edition 1.
tags
- A list of strings that users can use to filter and/or find instruments.
details
- User-facing metadata about the instrument (i.e., the information shown for the initial overview of an instrument).
details.title
- The title of the instrument should be the name of the instrument in title case (if applicable in the language). In most cases, this can be taken verbatim from a paper version of the instrument (e.g.,
'Happiness Questionnaire'
). - If a common short form of the name exists, it should be displayed in brackets after the full name (e.g.,
Happiness Questionnaire (HQ)
). This short name should be included for all languages. If a widely-known translated common short form is available it can be used (e.g.,'Questionnaire sur le bonheur (QB)'
), otherwise default to English (e.g.,'Questionnaire sur le bonheur (HQ)'
).
- The title of the instrument should be the name of the instrument in title case (if applicable in the language). In most cases, this can be taken verbatim from a paper version of the instrument (e.g.,
details.description
- A brief description of the instrument, such as the purpose and history of the instrument
content
- The form items (the content object) defines the content shown on the “content” page when completing an instrument (i.e., the fields used to uptake data).
content.kind
- Discriminator property for the type of field. The possible values depends on the type of data for this field.
content.variant
- The display structure for the field. The possible values depends on the field kind.
measures
- These are the outcomes of the instrument that are of relevance to users. In some cases, this may simply be a reference to fields in the instrument, or a computed value.
- Defines how raw data is displayed on the ODC frontend, such as in tables and graphs.
- Determines the summary page.
- Also included in data export.
validationSchema
- This defines the data model for the form, and corresponds one-to-one with the data structure that is ultimately stored in the database. As such, this is the most important part of the form definition, and should be defined before any fields.
Always consider using `group`ing to structure sections
Best Practices
- Name the directory and files and name in a long-form way to indicate what it is, prefix it with the PROJECT NAME only if the form is unique to the project.
- Name the output variables for the forms appropriately given the question and answer being provided.
- Remember that they will be prefixed with the form name when eventually dumped
- Consider the appropriate encoding for the data
- Is there a clear order of the values? If so, consider doing an ordered enum.
- Test your inputs against the validation schema
- Make sure your rules are correct given the paper form
- Please familiarize yourself with the possible validation rules here
- Be careful to write the most restrictive validation schema possible
- Example: likert-scale data should be
.int()
- Example: A select from multiple string options question should be
.enum(['option1','option2', ...])
instead of.string()
- Remember the API data-entry is independent of the form, so the validation schema must properly restrict API entry as well
- Example: likert-scale data should be
- Please make sure to format your code whenever possible, as this can prevent annoying issues with missing brackets. In the playground, you can do this with (Alt + F)
- If you find yourself repeating code frequently, consider extracting the logic into shared variables. The guiding principle of this should be to maximize readability.
- For example, if your data schema is
z.number().int().min(0).max(7)
for every field, consider moving it into a variable, as this can reduce the cognitive load of programmers reading your form - On the other hand, if this is the schema for only two or three variables, creating a variable would probably increase cognitive load, rather than reducing it.
- The same applies for computed measures (i.e., define a function at the top of your file instead of copy-pasting it to every field).
- For example, if your data schema is
- Review common styling conventions
- Use the playground to create instruments
- It is updated regularly to use the latest runtime
- It is setup with formatting, linting, and type checking by default
- Proper use of Zod’s enum type
- It is best to use Zod’s enum type when the answer to a form question is a set of constant values.
- Example: A question which asks the user to choose from a selection of options should use
z.enum([option1, option2, ...])
within its zod validation schema.