Dhis2
Basic DHIS2 API client for Ruby.
Installation
Add this line to your application's Gemfile:
gem 'dhis2' # get it from RubyGems
gem 'dhis2', github: 'BLSQ/dhis2' # OR get the bleeding edge version from github
And then execute:
$ bundle
Or install it yourself as:
$ gem install dhis2
Usage
Connection
The functionalities are available as a module. First thing you need to do is to connect to the instance:
- Global configuration (to call a single Dhis2 instance):
Dhis2.configure do |config|
config.url = "https://play.dhis2.org/2.28"
config.user = "admin"
config.password = "district"
config.version = "2.28"
end
::Dhis2.client.data_elements.list # => Array[<DataElement>,..]
# Or alternatively
::Dhis2.configure do |config|
url: "https://admin:district@play.dhis2.org/2.28",
version: "2.28"
)
::Dhis2.clientt.data_elements.list # => Array[<DataElement>,..]
- Local configuration: (in case you need to access different Dhis2 instances inside a single project):
configuration = Dhis2::Configuration.new.tap do |config|
config.url = "https://play.dhis2.org/2.28"
config.user = "admin"
config.password = "district"
config.version = "2.28"
end
client = ::Dhis2::Client.new(configuration.client_params)
client.data_elements.list # => Array[<DataElement>,..]
# Or alternatively
client = ::Dhis2::Client.new(
url: "https://admin:district@play.dhis2.org/2.28",
version: "2.28"
)
client.data_elements.list # => Array[<DataElement>,..]
Regarding SSL, there is an option to disregard SSL error messages (such as bad certificates). USE THIS AT YOUR OWN RISK - it may allow you to access a server that would return in error without it... but you cannot trust the response.
dangerous_configuration = Dhis2::Configuration.new.tap do |config|
config.url = "https://play.dhis2.org/2.28"
config.user = "admin"
config.password = "district"
config.version = "2.28"
config.no_ssl_verification = true
end
- Not sure of your version? Check it
Dhis2.get_version({ user: 'admin', password: 'district', url: 'https://play.dhis2.org/demo'})
Search for meta elements
All subsequent calls can be done on the objects themselves and are going to use the provided url and credentials
org_unit_levels = Dhis2.client.organisation_unit_levels.list
The various methods are taking an optional hash parameter to be used for ´filter´ and ´fields´ values:
org_units = Dhis2.client.organisation_units.list(filter: "level:eq:2", fields: %w(id level displayName parent))
If you want all fields, simply specify :all
org_units = Dhis2.client.organisation_units.list(filter: "level:eq:2", fields: :all)
Notes that any field found in the resulting JSON will be accessible from the object.
Raw data
By default, the gem transforms data from the api so you get underscore case. But this may not be needed and can hurt performance.
If you simply need raw data from your Dhis2:
org_units = Dhis2.client.organisation_units.list({}, true)
Pagination
Following the DHIS2 API, all calls are paginated - you can access the page info using the pager
property on the returned list:
org_units = Dhis2.client.organisation_units.list(filter: "level:eq:2", fields: %w(id level displayName parent))
org_units.pager.page # current page
org_units.pager.page_count # number of pages
org_units.pager.total # number of records
Get all paginated elements
It can be tedious to iterate over a paginated collection. Thus you can use fetch_paginated_data
which will get all pages for you and yield each element automatically.
Dhis2.client.organisation_units.fetch_paginated_data(
filter: "level:eq:2",
fields: %w(id level displayName parent)
).each do |organisation_unit, pager|
# do what you need here
end
# If you want pagination info in the loop:
Dhis2.client.organisation_units.fetch_paginated_data({
filter: "level:eq:2",
fields: %w(id level displayName parent)
},
{ with_pager: true}
).each do |organisation_unit, pager|
# do what you need here
end
# Dhis2.client.organisation_units.fetch_paginated_data is an Enumerable. If you want all objects in an array, without pager:
Dhis2.client.organisation_units.fetch_paginated_data.to_a
### Retrieve a single element
You can also retreive a single element using its id with `find`(in this case, all fields are returned by default):
```ruby
ou = Dhis2.client.organisation_units.find(id)
find
also accepts multiple ids - query will not be paginated and will return all fields for the given objects:
ous = Dhis2.client.organisation_units.find([id1, id2, id3])
An issue could arise if you try to get too many elements at once.
ous = Dhis2.client.organisation_units.find(super_long_array)
#=> would raise an exception because the generated url would be too long
# instead do
ous = Dhis2.client.organisation_units.find_paginated(super_long_array)
If you have an equality condition or set of equality conditions that should return a single element, you can use find_by
instead of the longer list option:
# Instead of this:
data_element = Dhis2.client.data_elements.list(filter: "code:eq:C27", fields: :all).first
# Just do:
data_element = Dhis2.client.data_elements.find_by(code: "C27")
Manage relations
You can add or remove items in collections using add_relation
and remove_relation
:
data_set = Dhis2.client.data_sets.list(page_size:1).first
data_element = Dhis2.client.data_elements.list(page_size: 1).first
data_set.add_relation(:dataSetElements, data_element.id)
...
data_set.remove_relation(:dataSetElements, data_element.id)
Values
You can retreive data values this way:
ds = Dhis2.client.data_sets.find_by(name: "Child Health")
organisation_unit = Dhis2.client.organisation_units.find_by(name: "Baoma")
period = "201512"
value_sets = Dhis2.client.data_value_sets.list(
data_sets: [ds.id],
organisation_unit: organisation_unit.id, periods: [period]
)
Supported items
The API is currently limited to actions on the following elements:
Analytic
Attribute
CategoryCombo
CategoryOptionCombo
DataElement
DataElementGroup
DataSet
DataValue
DataValueSet
Events
Indicator
IndicatorGroup
-
LegendSet
(Only list & find) OrganisationUnit
OrganisationUnitGroup
OrganisationUnitLevel
Program
ProgramIndicator
ProgramIndicatorGroup
Report
ReportTable
ResourceTables
SystemInfo
User
Update
Full update
You can update a given item by retreiving it using its id, making any modification on it then calling "update":
org_unit = Dhis2.client.organisation_units.find(id)
org_unit.short_name = "New Short Name"
org_unit.update
This uses DHIS2 "full update" ('PUT') and not the "partial update" feature (see below), so it requires a fully formed object to work (get it either with find
which takes all the fields or with the `fields: :all´ option).
Partial update
You can update a single or more attributes via the "update_attributes" method:
org_unit = Dhis2.client.organisation_units.list(fields: :all, filter: "name:eq:#{org_unit_name}").first
new_attributes = { name: "New name" }
org_unit.update_attributes(new_attributes)
Note that partial updates will no work with custom attributes at this time (while the full update will)
Create
A very basic write use case exists for DataElement
:
data_element = Dhis2.client.data_elements.create({
name: "TesTesT1",
short_name: "TTT1"
})
We do validate arguments and the response status. Dhis2::CreationError
exception is raised in case of error.
Bulk create
Whenever you need to create many elements at the same time, you can use bulk_create
:
elements = [
{ name: "TesTesT1", short_name: "TTT1" },
{ name: "TesTesT2", short_name: "TTT2" }
]
summary = Dhis2.client.data_elements.bulk_create(elements)
# would raise Dhis2::BulkCreationError on error
summary.imported_count # => 1
summary.updated_count # => 1
summary.ignored_count # => 0
Raw input
You might have data in camel case already and need to use it as is. In this case, we do not validate your input and do not create an object out of the response. Yet we validate the object has been properly created and return the plain response from the API.
response = Dhis2.client.data_elements.create({
name: "TesTesT1",
shortName: "TTT1"
}, true)
summary = Dhis2.client.data_elements.bulk_create([{
name: "TesTesT1",
shortName: "TTT1"
}], true)
Trigger analytics
You can trigger Analytics with
Dhis2.client.resource_tables.analytics
Raw output
To get raw data from Dhis2, ie no underscore case, no object, just plain json, you can specify you want the raw output:
client.data_elements.list({}, true)
#returns a PaginatedArray which elements look like:
{"id"=>"FTRrcoaog83", "displayName"=>"Accute Flaccid Paralysis (Deaths < 5 yrs)"}
client.data_elements.fetch_paginated_data({}, { raw: true }) do |data_element|
# use data_element as hash
end
Instantiating objects
It can be tedious to manually type Dhis2::Api::Version228::DataElement
(or any other class) and adapt it for each version number.
There is a convenient method to get it directly:
Dhis2::DataElement["2.28"]
#=> Dhis2::Api::Version228::DataElement
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run bundle exec rake test
and bundle exec rspec
to run the tests. Note that the tests are using the DHIS2 demo server, which is reset every day but can be updated by anyone - so if someone change the password of the default user, the tests are going to fail.
You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
deployment to rubygems.org
one time setup
gem install gem-release
curl -u rubygemaccount https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials
chmod 0600 ~/.gem/credentials
gem bump --tag --release
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/BLSQ/dhis2. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Please use Semantic versioning when bumping versions: Mj.Mn.P
- MAJOR version when you make incompatible API changes
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
License
The gem is available as open source under the terms of the MIT License.