This is a one-stop-shop for all systems that need access to the SORMAS data:
- Synchronization of data with the SORMAS Android app
- Data access for the SORMAS Angular web app
- Exchanging data with other SORMAS instances
- External services like symptom diaries or citizen applications
- Synchronization of data with other surveillance or to data analysis systems
Access to the API is by default restricted by HTTP Basic authentication. Using OIDC/OAUTH2/Bearer authentication is also possible depending on how keycloak is set up. See Authentication & Authorization.
For basic auth use the username and password as credentials for your HTTP requests. The user needs to have a user role having the SORMAS_REST user right.
The SORMAS REST API is documented automatically. The OpenAPI specification files are generated during the build process
and can be found at ${Project Root}/sormas-rest/target/swagger.{json,yaml}
.
You can render the OpenAPI specification with tools like editor.swagger.io. This allows you to inspect endpoints and example payloads, generate a matching API client for many languages, and to easily interact with the API of a live instance.
The OpenAPI files are generated with the swagger-maven-plugin
and the Swagger Annotation Framework[1].
If you are only interested in the OpenAPI specification files, you may either download a recent SORMAS
release where the files reside in the openapi
directory, take a look at the files in sormas-rest
, or execute the following command inside the sormas-base
module's
directory to build them for yourself:
# Requires Maven to be installed!
mvn package --projects ../sormas-rest --also-make -Dmaven.test.skip=true
The specification files are created at the path specified above.
[1] Swagger Annotations Guide on GitHub: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Annotations
The purpose of this API is to enable communication between SORMAS and other symptom journals.
Only users with the role REST_EXTERNAL_VISITS_USER
are authorized to use the endpoints. Authentication is done using
basic auth, with the user and password. For technical details please contact the dev team on
GitHub Discussions.
Follow up in SORMAS is done via visits. Visits hold information about symptoms at a specific time point. Visits can be created for cases and contacts, either via the SORMAS-UI or the external visits journal API.
This is a very basic concept that one needs to understand when working with visits. In SORMAS, a person entity represents a physically existing person. Cases and contacts represent epidemiological occurrences. When a person was in contact with an infectious environment, the person has a contact in SORMAS. When the person was in contact with such environments twice, it gets two contacts. When a person falls ill, it gets a case with the according disease. This means: In SORMAS, each contact and case relates to exactly one person. One person can have several contacts and cases, though. Follow up is done for a contact (or a case, which can be enabled in the SORMAS feature configuration). Contacts (or cases) initiate follow up. A person, though, either shows symptoms or not. It can not show symptoms for just one contact and not for the other. Thus, visits are related to all active contacts (and cases) of a person. Also, the communication with external symptom journals is PERSON BASED. Only the person uuid is used, visits are uploaded to each active case and contact of a person.
It is important to understand the meaning of two variables: the follow-up status and the symptom journal status.
The follow-up status describes the follow-up for a contact or a case. Possible values are defined in the FollowUpStatus enum
Follow up can be done with, or without an external journal, the follow-up status makes no distinction there. Because the
follow-up status is contact and case specific,but the communication with external journals is person based, SORMAS
determines the most important follow-up status of all contacts and cases related to the person in question when
communicating with external journals. Whenever there is follow-up ongoing for any of the persons contacts (and cases if
the case follow-up feature is enabled in SORMAS), SORMAS will state the FollowUpStatus.FOLLOW_UP
for that person
towards external journals.
The SymptomJournalStatus describes the state of a person related to external symptom journals. It is not contact or case specific.
In the domain folder, there is a sormas.properties. it holds the following values relevant for an external journal:
-
interface.patientdiary.authurl
: used to fetch an authentication token (see 1. below). -
interface.patientdiary.frontendAuthurl
: URL used to retrieve tokens for frontend requests. If not specified, no tokens will be fetched for such. -
interface.patientdiary.tokenLifetime
: Lifetime of tokens fetched via the authurl or the frontendAuthurl. To be specified in seconds. Can be set to 0 for no token caching. Defaults to 21600 (6 hrs.). -
interface.patientdiary.probandsurl
: used to register new persons in the external journal (see 2. below). -
interface.patientdiary.url
: used to open a person in the external journal (see 6. below). -
interface.patientdiary.email
: used to authenticate at the external journal (see 1. below). -
interface.patientdiary.password
: used to authenticate at the external journal. -
interface.patientdiary.defaultuser.username
: This user will be created in SORMAS and can be used by the external journal to authenticate. -
interface.patientdiary.defaultuser.password
: The above user's password. -
interface.patientdiary.acceptPhoneContact
: used to configure whether the phone number is considered relevant for registering a person in the external journal. It affects the validation of persons in SORMAS (see 2. below). Defaults to true
POST to the interface.patientdiary.authurl
.
Request body:
{
"email" : [patientdiary.email],
"password" : [patientdiary.password]
}
where [patientdiary.email]
is replaced with interface.patientdiary.email
and [patientdiary.password]
with
interface.patientdiary.password specified
in the sormas.properties
.
Expected response body:
{
"success" : true,
"userId" : [some-user-id],
"token" : [token]
}
The token
returned will be used to authenticate in other requests. Its lifetime can be configured via the
interface.patientdiary.tokenLifetime
property.
One special scenario is fetching a token for frontend calls (see 6.): When the interface.patientdiary.frontendAuthurl
is configured, it is used instead of the interface.patientdiary.authurl
here. If it is not configured, no token will
be used.
This process involves several steps that are triggered via the REGISTER
button a privileged user can see in the top
right corner when having opened a case or a contact.
To be able to see this button, the user must have at least one of the following user roles: national user, contact supervisor, contact officer, community officer, surveillance officer, surveillance supervisor, or admin supervisor.
First comes a SORMAS-internal validation of contact details.
The person to be registered needs to have at least an email address (or a phone number if that is accepted for
registration, see interface.patientdiary.acceptPhoneContact
) to pass this validation.Also, when there are several
email addresses or phone numbers, one of them has to be marked primary contact detail, so that it is clear which contact
detail shall be used.
Then comes an external validation of the contact details. For this, SORMAS fetches an authentication token as in 1. Then it sends a GET request to the following URL for each contact detail to be used in the external journal:
GET [interface.patientdiary.probandsurl]/probands?q=[URL-encoded-query-parameter-and-value]
, with a header like
x-access-token: [token]
.
The [URL-encoded-query-parameter-and-value]
consists of a parameter-value-pair. The parameter is either Email
or
Mobile phone
. The value holds the contact detail to be validated.
An unencoded example for this is "Email" = "[email protected]"
, the URL-encoded version is
%22Email%22%20%3D%20%22example%40example.de%22
.
[token]
is replaced with the token fetched for authorization.
The CURL equivalent for an exemplary call is
curl --request GET 'https://probands-URL.com//probands?q=%22Email%22%20%3D%20%22example%40example.de%22' --header 'x-access-token: my-access-token'
.
Expected result is a PatientDiaryQueryResponse
which information about any person already registered in the external
journal and using the same contact detail.
It needs to be structured as follows:
PatientDiaryQueryResponse {
total: integer,
count: integer,
results: List<PatientDiaryPersonData>
}
-
total
should state how many persons are registered in the external journal (this information is currently never used in SORMAS). -
count
should state how many registered persons using the same contact detail were found. -
results
need to contain a PatientDiaryPersonData for each match:
PatientDiaryPersonData {
_id: string,
idatId: PatientDiaryIdatId
}
_id
should be a unique identifier for the person this data is about (this information is currently never used in SORMAS)
The PatientDiaryIdatId
needs to be structured as follows:
PatientDiaryIdatId{
idat: PatientDiaryPersonDto
}
The PatientDiaryPersonDto
holds the actual person data:
PatientDiaryPersonDto{
personUUID: string,
firstName: string,
lastName: string,
gender: string,
birthday: string,
contactInformation: PatientDiaryContactInformation,
endDate: string
}
personUUID
should be the UUID of the person in SORMAS. This UUID is used to sync with external journals (this information is currently never used in SORMAS).firstName
andlastName
need to hold the first and last name of the person.gender
should hold the persons gender (this information is currently never used in SORMAS).birthday
should hold the person's birthday (this information is currently never used in SORMAS).contactInformation
should hold the contact information of that person, which should for logical reasons always contain (at least) the contact detail provided by SORMAS in the query.endDate
should hold the date after which follow up is supposed to be stopped by the external journal.
PatientDiaryIdatId {
email: string,
phone: PatientDiaryPhone
}
email
should hold the email address for the personphone
should hold the phone number of that person:
PatientDiaryPhone {
number: string,
internationalNumber: string,
nationalNumber: string,
countryCode: string,
dialCode: string,
}
To put this all together, here is an example PatientDiaryQueryResponse
with one person using the same contact detail:
{
"total" : 100,
"count" : 1,
"results" : [{
"_id" : "60586691d4c30700119515c8",
"idatId" : {
"idat" : {
"contactInformation" : {
"phone" : null,
"email" : "[email protected]"
},
"personUUID" : "RMTEF2-UZXCXE-7YBJK6-KUMSSEME",
"firstName" : "Maria",
"lastName" : "Muster",
"gender" : "female",
"birthday" : null
}
}
}]
}
SORMAS allows to continue with the registration of a new person only when the person has a unique first name, so when
all persons of the response have a different one (or if the response does not contain any matches, which needs to show
in PatientDiaryQueryResponse.count == 0
). This validation is necessary to avoid confusion of person related data in
some external journals.
When there are no validation errors in the process described above, SORMAS fetches an authentication token as described in 1. and then uses it to request the external journal to register the person:
POST [interface.patientdiary.probandsurl]/external-data/[personUUID]
.
The [personUUID]
is replaced with the UUID of the person, which is later used to sync data between the external
journal and SORMAS.
Expected response body:
{
"success" : [boolean],
"message" : [messageString]
}
[boolean]
is expected to be true in case of successful registration. SORMAS then sets the symptom journal status to
REGISTERED
and displays the message to the user.
When [boolean]
is false, the message is shown as an error to the user.
To fetch data relevant for the registration, the external journal can use the /visits-external/person/{personUuid}
API endpoint described below.
It may happen that person data (like a contact detail) gets changed after a person is registered in an external journal. SORMAS notifies external journals about such a change with first fetching an authentication token as descriced in 1., and the using this token for this request:
PUT [interface.patientdiary.probandsurl]/external-data/[personUUID]
The external journal is expected to refetch the person data via the /visits-external/person/{personUuid}
API endpoint
described below and save the changes.
After re-fetching the person data, the symptom journal does its own internal validation and responds to SORMAS with the synchronization result, containing eventual validation errors.
The expected response body:
{
"success" : [boolean],
"message" : [messageString],
"errors" : [{
"errorKey": [errorString]
}]
}
If the changes were done manually by a user from the person edit form, the synchronization result is shown to the user in a popup window, so that the user can fix eventual errors and resynchronize the person data.
For this, the /visits-external
API endpoint has to be used. This is described below.
For this, the /visits-external/person/{personUuid}/status
API endpoint is to be used. This is described below.
Once the symptom journal status of a person is set to REGISTERED
or ACCEPTED
, the external journal button in the
SORMAS-UI changes. It does not provide a registration anymore, but the options to open the person in the external
journal and to cancel external follow up. This button can be found when having opened a contact (or a case if the case
follow-up feature is enabled in SORMAS) in the top right corner. If the user chooses to open the person in the external
journal, SORMAS opens a new browser tab with the following URL:
[interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier
SORMAS expects the external journal to present a view of the person there.
If the interface.patientdiary.frontendAuthurl
is configured, SORMAS fetches an authentication token as described in 1,
and appends it to the URL:
[interface.patientdiary.url]/data?q=[personUuid]&queryKey=sicFieldIdentifier&token=[token]
As described above, the journal button can offer the option to cancel external follow up. If a user choses this option, SORMAS fetches an authentication token as described in 1., and uses it to request:
DELETE [interface.patientdiary.probandsurl]/external-data/[personUUID]
Expected response body:
{
"success" : [boolean],
"message" : [messageString]
}
[boolean]
is expected to be true in case of successful deletion. SORMAS then sets the symptom journal status to
DELETED
and displays the message to the user.
When [boolean]
is false, the message is shown as an error to the user.
Please note that this does not affect any follow-up status. Cancelling follow up of a contact or case is independent of cancelling external follow up of a person.