Outbound is only available in Medic 3.5.0 and above
Outbound push allows configurers to have the creation or editing of CouchDB documents trigger outbound REST requests using the data in that document. For example, upon receiving a referral report you could send that referral to an external facility system that will manage and process that event.
These triggers can apply to all document types (not just common types such as reports or contacts) and as such care should be taken to only send the documents you intend (see configuration of relevant_to
below).
For outbound pushes to occur, you must enable the mark_for_outbound
transition in config:
{
"transitions": {
"mark_for_outbound": true
}
}
The rest of the configuration is against the outbound
configuration property, which allows you to configure as many outbound pushes as you like, keyed off a unique name:
{
"outbound": {
"first config": {
"relevant_to": "...",
"destination": {},
"mapping": {}
},
"second config": { }
}
}
Each outbound push configuration contains the following properties: relevant_to
, destination
and mapping
.
An “expression” (some JS code that resolves to a truthy or falsy value) that determines whether this configuration is relevant to a document. The document is passed to the expression as doc
, and if relevant is fully hydrated before being passed (i.e. the attached contact, its parents etc are fully attached instead of just being stubs).
Example: you want to send a referral to a facility’s EMR system when a CHW refers a patient:
{
"relevant_to": "doc.type === 'data_record' && doc.form === 'referral'"
}
Note: all documents that Sentinel processes can be picked up by your configuration, so it’s important to correctly configure relevant_to
. Checking the document type as shown above is probably a good start.
A complex property that defines the details of the connection to the external service. It currently supports several authentication types: basic authentication, HTTP authorization request header, and a custom authentication mode for Muso SIH.
Basic auth example:
{
"destination": {
"base_url": "https://example.com",
"auth": {
"type": "basic",
"username": "admin",
"password_key": "example.com"
},
"path": "/api/v1/referral"
}
}
Here password_key
is a key used to find the password in CouchDB’s node-based configuration. See Credentials section below.
If you don’t provide an authentication parameter then the request will be sent without authentication.
As of 3.9, the header
type is also supported, which sends authentication credentials via a HTTP request header: Authorization: '<value>'
. The value is set in the CouchDB configuration, and referred to by the value_key
, similarly to the password_key
. The value must match the credentials needed for the third party tool, and is generally formatted as <type> <credentials>
. For instance, to send data to RapidPro, the value in the configuration would be set to the complete RapidPro API Token: eg Token 123456789abcdef
.
Header auth example:
{
"destination": {
"base_url": "https://example.com",
"auth": {
"type": "header",
"name": "Authorization",
"value_key": "example.com"
},
"path": "/api/v1/referral"
}
}
A complex property that declares how the payload to be sent to the destination
should be created.
Each key is a string object path to a location in the payload, and each value is either:
path
property that represents a string object path as above, or an expr
property which is an expression similar to relevant_to
to determine the resulting value. If you wish for the value to be optional (that is to say it’s OK if path
or expr
evaluate to undefined
) you may also set optional
to true
Given the following example (incomplete) report:
{
"id": "abc-1234",
"type": "data_record",
"form": "referral",
"reported_date": 1555069530966,
"fields": {
"patient_id": "12345",
"patient_temp_deg_F": 100,
"danger_signs": ["V", "BL", "D", "IG"]
},
"contact": {
"_id": "def-5678",
"name": "Jane CHW",
"parent": {
"_id": "hij-9012",
"name": "..."
}
}
}
The following mapping configuration:
{
"mapping": {
"patient_id": "doc.fields.patient_id",
"chw_id": "doc.contact._id",
"event.temp_c": {
"expr": "((doc.fields.patient_temp_deg_F - 32) * (5.0/9.0)).toFixed(2)"
},
"event.in_danger": {
"expr": "doc.fields.danger_signs.length >= 3 ? true : undefined",
"optional": true
},
"event.additional_notes": {
"path": "doc.fields.notes",
"optional": true
}
}
}
Would create the following JSON payload to send:
{
"patient_id": "12345",
"chw_id": "def-5678",
"event": {
"temp_c": 37.78,
"in_danger": true
}
}
This example makes a few points:
doc
in both path
and expr
propertiesoptional
, it won’t exist at all in the payload if the resulting value is undefined
, either because that is the result of executing the expr
, or the path
doesn’t exist. Note that if the event.in_danger
expression was instead doc.fields.danger_signs.length >= 3
the property in_danger
would always exist and would either be true
or false
path
or an expr
. Given doc.foo.bar.smang
as a path where any of those properties may not exist in the doc:path
just use the path as is, if any part of the path is undefined
the resulting value will safely be undefined
expr
you do need to handle this situation: doc.foo && doc.foo.bar && doc.foo.bar.smang
expr
expressions throw an exception (for example because you didn’t handle potentially undefined
properties as noted above) your push will failpath
declarations result in an undefined
value and you have not also declared that property optional your push will failTo securely store credentials, we’ll be using CouchDB’s config storage, as this is a convenient location that only CouchDB administrators can access.
Passwords are stored under the medic-credentials
section, under the key declared in config.
In the following example:
{
"destination": {
"base_url": "https://example.com",
"auth": {
"type": "basic",
"username": "admin",
"password_key": "example.com"
},
"path": "/api/v1/referral"
}
}
We have our key configured to example.com
. This means that in CouchDB’s admin config we would expect to find a password at medic-credentials/example.com
.
To add the credential to the admin config you need to either PUT the value using curl or similar:
curl -X PUT https://<user>:<pass>@<domain>/_node/couchdb@127.0.0.1/_config/medic-credentials/example.com -d '"the-real-password"'
(Note that couchdb@127.0.0.1
is the local node name, and may be different for you depending on your setup.)
You can also add it via Fauxton:
Add Option
Section
should be medic-credentials
, the Name
should be (in this example) example.com
and the value should be the passwordCreate
Send semantics have changed over the course of developing this feature, and are important to understand for your deployment to be successful.
mapping
property) is different from the most recent outbound push performed for this document and configuration.It’s important to understand that if your mapping
configuration produces a different result every time it’s run you may experience Outbound sending the “same” data many more times than you’d expect.
For example, if you want a timestamp in your payload you could configure it like this:
{
"timestamp": {"expr": "new Date()"}
}
Outbound may send your request multiple times even if the user just hit save once. If this is a problem for your deployment, consider using values on the document itself that will not change every time your mapping is executed:
{
"timestamp": "doc.timestamp"
}
The outbound feature is used for sending data to an external service. If you are looking to receive data from an external service, take a look at the records api.
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.