Server Protocol

The Net4Care framework is based upon Java and provides a plugable architecture for reconfiguring serialization and server communication. However, as of release 0.4, we have decided to elevate two particular serialization and server connection schemes to become standards as this allows clients in other languages to communicate with a common server. In version 0.6 we stopped using a 2-element wrapper array for embedding the type identifier, because that prevented the use of standard JSON serializers. Instead the type identifier is included as a separate meta-property.

The standard implementations are

  1. REST over HTTP(S) for client-server protocol.
  2. JSON encoding for serialization of message payload.

Both are explained in detail below.

WARNING

THE INFORMATION BELOW IS LOW LEVEL DOCUMENTATION OF THE INTERFACE AND SHOULD NOT BE USED DIRECTLY IF THERE IS A LANGUAGE BINDING (CURRENTLY JAVA AND C#) AS THERE IS NO CHECKING ON THE SERVER SIDE.

HTTP REST Protocol

A standard Net4Care server is a web server (Java servelet) bound to the path ".../observation".

Thus to verify that a local server is up and running go to http://localhost:8082/observation. You should now see a page stating the server's version and some documentation about the REST interface.

The server responds to two REST operations, POST and GET.

  • POST: Use POST on the /observation path to upload observations.
  • GET: Use GET on the /observation path to query sets of observations from the server. You can retrieve observations in either the originally sent JSON format or in the XML format of Personal Health Monitoring Records.

For details, see below.

JSON Encoding

Uploading observations (POST)

In order to upload an observation to the server instance, send a POST request to http://localhost:8082/observation. The body of the POST request must be a representation of the tele observation in JSON format.

The server does two things with the JSON body which are important to understand when interfacing the server:

  1. It stores the JSON message verbatim in the ObservationCache. If a client later requests observations for a given patient in a given time interval, these JSON messages are returned without any conversion from the ObservationCache. This means a client is free to define any extra attributes in the client (such as questionaire answers, comments, etc.) and bind them to JSON key-value pairs.
  2. It makes a partial parsing of the JSON message, looking for clinical quantities which are encoded using specific structures and keys in the JSON. This is done in order to generate the HL7 PHMR document that is stored in the XDS.b storage tier. This poses a number of constraints on the JSON format while leaving others open, as outlined below. This also means that only clinical quantities at the moment are converted into the PHMR format.

First, let us look at an example message:

POST /observation HTTP/1.1
User-Agent: Java/1.6.0_23
Host: localhost:8082
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-type: application/x-www-form-urlencoded
Content-Length: 825

{
    "patientCPR": "251248-4916",
    "organizationUID": "org.net4care.org.mycompany",
    "treatmentID": "treatment-id",
    "time": 1338386271775,
    "codeSystem": "2.16.840.1.113883.6.1",
    "deviceDescription": {
        "type": "Spirometer",
        "model": "SpiroCraft-II",
        "manufacturer": "MyCompany",
        "serialId": "584216",
        "partNumber": "69854",
        "hardwareRevision": "2.1",
        "softwareRevision": "1.1",
        "deviceClassification": "Klasse-1",
        "calibrationDate": 1370338386848
    },
    "observationSpecifics": {
        "fvc": {
            "value": 0.1,
            "unit": "L",
            "code": "19868-9",
            "displayName": "FVC",
            "contextCodeList": []
        },
        "fev1": {
            "value": 0.01,
            "unit": "L",
            "code": "20150-9",
            "displayName": "FEV1",
            "contextCodeList": []
        },
        "observationAsHumanReadableText": "Measured: FVC:0.1 L / FEV1:0.01 L"
    },
    "comment": "",
    "deviceDescriptionAsHumanReadableText": "Device properties: Type: Spirometer Model: SpiroCraft-II Manufacturer: MyCompany Serial No: 584216 Part No: 69854 Hardware Revision: 2.1 Software Revision: 1.1."
}

The first part of this JSON is mandatory and you must use the particular key and provide a proper value of correct type:

    "patientCPR": "251248-4916",
    "organizationUID": "org.net4care.org.mycompany",
    "treatmentID": "treatment-id",
    "time": 1338386271775,
    "codeSystem": "2.16.840.1.113883.6.1",
    "deviceDescription": {
        "type": "Spirometer",
        "model": "SpiroCraft-II",
        "manufacturer": "MyCompany",
        "serialId": "584216",
        "partNumber": "69854",
        "hardwareRevision": "2.1",
        "softwareRevision": "1.1",
        "deviceClassification": "Klasse-1",
        "calibrationDate": 1370338386848
    },

These key-value pairs are simply JSON equivalents of the attributes you define in a StandardTeleObservation as outlined in the Defining Observations tutorial.

Note that the time value must be encoded in UNIX long format.

The actual encoding of clinical observations (the class implementing ObservationSpecifics in the Java case) is slightly more loosely defined:

    "observationSpecifics": {
        "fvc": {
            "value": 0.1,
            "unit": "L",
            "code": "19868-9",
            "displayName": "FVC",
            "contextCodeList": []
        },
        "fev1": {
            "value": 0.01,
            "unit": "L",
            "code": "20150-9",
            "displayName": "FEV1",
            "contextCodeList": []
        },
        "observationAsHumanReadableText": "Measured: FVC:0.1 L / FEV1:0.01 L"
    }

The mandatory key-value pairs and structure are marked in bold

"observationSpecifics": {
    <name of property, e.g.: "fvc"> : {
        "value": <value as decimal number, e.g.: 0.1>,
        "unit": <unit as string, e.g.: "L">,
        "code": <code as string, e.g.: "19868-9">,
        "displayName": <display name as string, e.g.: "FVC">,
        "contextCodeList": [ <list of context codes> ]
    },
    <more observations here>
     "observationAsHumanReadableText": <observation in plain text, e.g. "Measured: FVC:0.1 L / FEV1:0.01 L">
}

That is: 1) The clinical quantities must be a set of JSON object with keys "value", "unit", "code", "displayName", and "contextCodeList". The value domains are those of the ClinicalQuantity class explained in Defining Observations; 2) the nesting structure of the JSON objects must be as outlined above; 3) some key strings are used by our Java serializer on the client side but you are free to use other values as they are not used on the server side (those marked "(any string)" above.)

(For all the gory details, please consult the Java class ServerJSONSerializer in n4c_serializer folder.)

Context Codes

In release 0.5 we introduced context codes (translates into HL7 'methodCode'). If you use context codes, the "contextCodeList" is non-empty.

The format of course reflects that of a list of ContextCode objects.

"contextCodeList": [ {
      "code":"CL",
      "displayName":"Målt af kliniker",
      "codeSystem":"2.16.840.1.113883.3.1558.1.1"
    }, {
      "code":"EL",
      "displayName":"Elektronisk overførsel",
      "codeSystem":"2.16.840.1.113883.3.1558.1.2"
    } 
]

Querying for observations (GET)

You can query the server using a GET request. The input URL must be on the form:

GET /observation?cpr=<cpr>&intervalstart=<timestamp>&intervalend=<timestamp>&codelist=<codelist>&codesystem=<codesystem>&QueryType=<querytype>&format=<format> HTTP/1.1

where the request parameters should be interpreted as:

  1. cpr is the patients social security number.
  2. intervalstart is the beginning of the time interval to query for. <timestamp> is a UNIX timestamp in milliseconds.
  3. intervalend is the end of the time interval to query for.
  4. codelist is the list of clinical codes to query for. <codelist> is in the JSON format |c1|c2|...|cn| where ci is a valid code according to the codesystem.
  5. codesystem specifies which code system the codelist is using, using its HL7 OID. It could be LOINC or IUPAC or another supported system.
  6. querytype Specifies the type of query. Currently (release 0.4)) there are two types of queries that your can use:
    • PersonTimeQuery Query a person in a specific time interval. Here the cpr, intervalstart and intervalend parameters are mandatory.
    • PersonTimeTypeQuery Query a person in a specific time interval and query for a specific codesystem (e.x. LOINC) and a specific list of codes. In this query the cpr, intervalstart, intervalend, codesystem and codelist parameters are mandatory.
  7. format The return format. Currently there are 3 formats available: 'application/json', and 'application/xml'.

For a description of code systems and codes, please refer to our tutorial Defining Observations.

If you do not include all the above parameters the server will properly fail executing the request!

Here is a concrete example of a query request and the matching response. First the simple query (PersonTimeQuery).

GET /observation?QueryType=PersonTimeQuery&cpr=251248-4916&format=application%2Fjson&intervalend=1355222100000&intervalstart=1355133600000 HTTP/1.1
accept: application/json
User-Agent: Java/1.7.0
Host: localhost:8082
Connection: keep-alive
X-Forwarded-For: 127.0.0.1

HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Transfer-Encoding: chunked
Server: Jetty(6.1.x)

367
["{\"patientCPR\":\"251248-4916\",\"organizationUID\":\"MyOrgID\",\"treatmentID\":\"myTreatmentId\",\"time\":1355221858980,\"codeSystem\":\"2.16.840.1.113883.6.1\",\"deviceDescription\":{\"type\":\"Spirometry\",\"model\":\"MODEL1\",\"manufacturer\":\"Manufac1\",\"serialId\":\"1\",\"partNumber\":\"1\",\"hardwareRevision\":\"1.0\",\"softwareRevision\":\"1.0\"},\"observationSpecifics\":{\"fvc\":{\"value\":3.9,\"unit\":\"L\",\"code\":\"19868-9\",\"displayName\":\"FVC\"},\"fev1\":{\"value\":3.3,\"unit\":\"L\",\"code\":\"20150-9\",\"displayName\":\"FEV1\"},\"observationAsHumanReadableText\":\"Measured: FVC:3.9 L / FEV1:3.3 L\"},\"comment\":\"\",\"deviceDescriptionAsHumanReadableText\":\"Device properties: Type: Spirometry Model: MODEL1 Manufacturer: Manufac1 Serial No: 1 Part No: 1 Hardware Revision: 1.0 Software Revision: 1.0.\"}"]
0

Next the more advanced query (PersonTimeTypeQuery).

GET
/observation?cpr=251248-4916&intervalend=1346140080000&intervalstart=1346053680000&codesystem=2.16.840.1.113883.6.1&codelist=|19868-9|20150-9|&querytype=PersonTimeTypeQuery&format=application%2Fjson HTTP/1.1
User-Agent: Java/1.6.0_23-ea
Host: localhost:8082
Connection: keep-alive
X-Forwarded-For: 127.0.0.1

HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Transfer-Encoding: chunked
Server: Jetty(6.1.x)

["{\"patientCPR\":\"251248-4916\",\"organizationUID\":\"org.net4care.org.mycompany\",\"treatmentID\":\"treatment-id\",\"time\":1327223534508,\"codeSystem\":\"2.16.840.1.113883.6.1\",\"deviceDescription\":{\"type\":\"Spirometer\",\"model\":\"SpiroCraft-II\",\"manufacturer\":\"MyCompany\",\"serialId\":\"584216\",\"partNumber\":\"69854\",\"hardwareRevision\":\"2.1\",\"softwareRevision\":\"1.1\"},\"observationSpecifics\":{\"fvc\":{\"value\":2.0,\"unit\":\"L\",\"code\":\"19868-9\",\"displayName\":\"FVC\"},\"fev1\":{\"value\":1.2,\"unit\":\"L\",\"code\":\"20150-9\",\"displayName\":\"FEV1\"},\"observationAsHumanReadableText\":\"Measured: FVC:2.0 L / FEV1:1.2 L\"},\"comment\":\"\",\"deviceDescriptionAsHumanReadableText\":\"Device properties: Type: Spirometer Model: SpiroCraft-II Manufacturer: MyCompany Serial No: 584216 Part No: 69854 Hardware Revision: 2.1 Software Revision: 1.1.\"}","{\"patientCPR\":\"251248-4916\",\"organizationUID\":\"org.net4care.org.mycompany\",\"treatmentID\":\"treatment-id\",\"time\":1338390318803,\"codeSystem\":\"2.16.840.1.113883.6.1\",\"deviceDescription\":{\"type\":\"Spirometer\",\"model\":\"SpiroCraft-II\",\"manufacturer\":\"MyCompany\",\"serialId\":\"584216\",\"partNumber\":\"69854\",\"hardwareRevision\":\"2.1\",\"softwareRevision\":\"1.1\"},\"observationSpecifics\":{\"fvc\":{\"value\":0.1,\"unit\":\"L\",\"code\":\"19868-9\",\"displayName\":\"FVC\"},\"fev1\":{\"value\":0.01,\"unit\":\"L\",\"code\":\"20150-9\",\"displayName\":\"FEV1\"},\"observationAsHumanReadableText\":\"Measured: FVC:0.1 L / FEV1:0.01 L\"},\"comment\":\"\",\"deviceDescriptionAsHumanReadableText\":\"Device properties: Type: Spirometer Model: SpiroCraft-II Manufacturer: MyCompany Serial No: 584216 Part No: 69854 Hardware Revision: 2.1 Software Revision: 1.1.\"}"]