Demographics API
Adds functionality to store demographic information on the server. See https://sagebionetworks.jira.com/wiki/spaces/MTB/pages/1934819724 and Demographic Survey Categories (somewhat outdated).
Type Checking
Currently, there is no type checking on demographic answer values, so all values are stored as strings. Type checking is a V2 goal.
App-Level vs. Study-Level
Routes are available for both app-level and study-level demographics. The idea is that some basic demographics might be collected during app onboarding which is not associated with a particular study, and then additional demographics data might be collected by a particular study within the app.
Routes
Saving
POST /v5/studies/{studyId}/participants/{userId}/demographics
Save/overwrite all demographics for a user
Study-level, posted on the user’s behalf (by researcher, study coordinator)
POST /v5/studies/{studyId}/participants/self/demographics
Save/overwrite all demographics for a user
Study-level, posted by the user
POST /v3/participants/{userId}/demographics
Save/overwrite all demographics for a user
App-level, posted on the user’s behalf (by app admin)
POST /v3/participants/self/demographics
Save/overwrite all demographics for a user
App-level, posted by the user
POST /v5/studies/{studyId}/participants/{userId}/demographics/assessment
Save/overwrite all demographics for a user
Study-level, posted on the user’s behalf (by researcher, study coordinator)
Uses the assessment JSON model
POST /v5/studies/{studyId}/participants/self/demographics/assessment
Save/overwrite all demographics for a user
Study-level, posted by the user
Uses the assessment JSON model
POST /v3/participants/{userId}/demographics/assessment
Save/overwrite all demographics for a user
App-level, posted on the user’s behalf (by app admin)
Uses the assessment JSON model
POST /v3/participants/self/demographics/assessment
Save/overwrite all demographics for a user
App-level, posted by the user
Uses the assessment JSON model
Deleting
DELETE /v5/studies/{studyId}/participants/{userId}/demographics/{demographicId}
Deletes a specific demographic (single category) for a particular user
Study-level, done by researcher or study coordinator
DELETE /v3/participants/{userId}/demographics/{demographicId}
Deletes a specific demographic (single category) for a particular user
App-level, done by app admin
DELETE /v5/studies/{studyId}/participants/{userId}/demographics
Deletes all of a user’s demographics
Study-level, done by researcher or study coordinator
DELETE /v3/participants/{userId}/demographics
Deletes all of a user’s demographics
App-level, done by app admin
Fetching
GET /v5/studies/{studyId}/participants/{userId}/demographics
Fetches all demographics for a user
Study-level, done by researcher/study-coordinator
GET /v3/participants/{userId}/demographics
Fetches all demographics for a user
App-level, done by app admin
GET /v5/studies/{studyId}/participants/demographics
Fetches all study-level demographics for all users within a study
Study-level, done by researcher/study-coordinator
GET /v3/participants/demographics
Fetches all app-level demographics for all users within an app
App-level, done by app admin
JSON Format
Unless otherwise stated, routes use the following schema (for a single user):
{
"userId": (read only) <string>,
"demographics": {
(category name): {
"id": (guid) (read only) <string>,
"multipleSelect": <bool>,
"values": [
<any>
]
"units": <string>
},
...
}
}
Example:
{
"userId": "userId1",
"demographics": {
"height": {
"id": "guid1",
"multipleSelect": false,
"values": [
72.0
]
"units": "m"
},
"race": {
"id": "guid2",
"multipleSelect": true,
"values": [
"Asian",
"Native Hawaiian or Other Pacific Islander"
]
}
}
}
Certain routes use an assessment response model for demographic input:
{
"stepHistory": [
{
"children": [
{
"identifier": <string> (category name),
"answerType": { (optional)
"unit": <string>
},
"value": <single value, any type OR array of single value, any type OR object with fields of single value, any type>
}
]
}
]
}
Although other fields may be included in the normal assessment model, all other fields are discarded for demographics use.
Example:
Internal model
SQL:
3 tables are used because each table has a one-to-many relationship with the table below it, both intuitively and in SQL, and this nested format is much simpler with multiple tables. It also allows convenient grouping by userId for a better JSON format.
DemographicsUsers
: maps to Java classDemographicUser
Contains all demographics for a single user
One-to-many with
Demographics
Demographics
: maps to Java classDemographic
Contains all values for a single demographic category for a single user
One-to-many with
DemographicsValues
DemographicsValues
: maps to Java classDemographicValue
Contains a single value in a demographic category
App-level demographics are represented with a null studyId.