Skip to content

Commit

Permalink
Merge pull request #21 from amanyiraho/fail-gracefully
Browse files Browse the repository at this point in the history
package fails gracefully
  • Loading branch information
amanyiraho authored Nov 21, 2024
2 parents 285833c + b1e21b2 commit 6586f1c
Show file tree
Hide file tree
Showing 14 changed files with 212 additions and 115 deletions.
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Imports:
R6 (>= 2.5.1)
Suggests:
covr,
httptest2,
knitr,
rmarkdown,
testthat
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export(Dhis2r)
import(R6)
import(httr2)
importFrom(attempt,message_if_not)
importFrom(attempt,stop_if_any)
importFrom(attempt,stop_if_not)
importFrom(curl,has_internet)
Expand Down
10 changes: 10 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
# dhis2r 0.3.0

## Improvements

* Updated the package to fail gracefully with an informative message if the resource is not available or has changed and doesn't give a check warning nor error

* Now API calls function print a massage "No internet connection!" if there is no internet connection instead of an error

* The url is of the queried API endpoint is printed using `message()` instead of `print()`

# dhis2r 0.2.1

## Bug fix
Expand Down
213 changes: 117 additions & 96 deletions R/connect.R
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
#'
#' @export
#'
#' @examples
#' @examplesIf interactive() && curl::has_internet()
#'
#' # Load dhis2r
#' library(dhis2r)
#' # connect to the DHIS2 instance
Expand Down Expand Up @@ -115,7 +116,7 @@ Dhis2r <- R6::R6Class(
self$request_sent <- self$request_sent |>
# req_url_query(paging = "false") |>
req_headers("Accept" = "application/json") |>
httr2::req_user_agent("dhis2r (http://www.amanyiraho.com/dhis2r/") |>
httr2::req_user_agent("dhis2r (http://www.dhis2r.amanyiraho.com/") |>
httr2::req_retry(max_tries = 5)

},
Expand All @@ -129,26 +130,31 @@ Dhis2r <- R6::R6Class(
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
get_user_info = function() {
# Check for internet
check_internet()
if(has_internet()){

response_object <- self$request_sent |>
req_url_path_append("me") |>
# req_error(body = dhis2_error_message) |>
req_perform()

response_object <- self$request_sent |>
req_url_path_append("me") |>
req_perform()
message(response_object$url)

print(response_object$url)
response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)
self$access_rights <- unlist(response_data[["access"]])

self$access_rights <- unlist(response_data[["access"]])
self$account_info <- unlist(list(response_data[["userCredentials"]][["createdBy"]][c("name", "username")], response_data["created"]))

self$account_info <- unlist(list(response_data[["userCredentials"]][["createdBy"]][c("name", "username")], response_data["created"]))
unlist( list( response_data["name"],
response_data["phoneNumber"],
response_data["email"]))

unlist( list( response_data["name"],
response_data["phoneNumber"],
response_data["email"]))

},
}else{
message("No internet connection!")
}
},
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#' @description
Expand All @@ -163,44 +169,46 @@ Dhis2r <- R6::R6Class(
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
get_metadata = function(endpoint = NULL, fields = c("name","id")) {

# Check for internet
check_internet()

if(is.null(endpoint)){
if(has_internet()){

response_object <- self$request_sent |>
req_url_path_append("resources") |>
req_perform()
if(is.null(endpoint)){

print(response_object$url)
response_object <- self$request_sent |>
req_url_path_append("resources") |>
req_perform()

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)
message(response_object$url)

tibble::tibble(response_data$resources)
response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)

}else{
tibble::tibble(response_data$resources)

}else{

attempt::stop_if_not(endpoint, is.character, "endpoint should be type character")

response_object <- self$request_sent |>
req_url_path_append(endpoint) |>
req_url_query(fields = paste0(fields, collapse = ",")) |>
req_perform()
attempt::stop_if_not(endpoint, is.character, "endpoint should be type character")

print(response_object$url)
response_object <- self$request_sent |>
req_url_path_append(endpoint) |>
req_url_query(fields = paste0(fields, collapse = ",")) |>
req_perform()

message(response_object$url)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)

tibble::tibble( response_data[[1]])
tibble::tibble( response_data[[endpoint]])

}
}

},
}else{
message("No internet connection!")
}
},
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#' @description Get all possible fields for a specific metadata resource from a DHIS2 instance
Expand All @@ -212,25 +220,29 @@ Dhis2r <- R6::R6Class(
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
get_metadata_fields = function(endpoint) {
# Check for internet
check_internet()
attempt::stop_if(endpoint, is.null, "endpoint shouldnot be NULL")
attempt::stop_if_not(endpoint, is.character, "endpoint should be type character")

response_object <- self$request_sent |>
req_url_path_append(endpoint) |>
req_url_query(fields = ":all") |>
req_url_query(paging = "true") |>
req_url_query(pageSize = "1") |>
req_perform()
if(has_internet()){

attempt::stop_if(endpoint, is.null, "endpoint shouldnot be NULL")
attempt::stop_if_not(endpoint, is.character, "endpoint should be type character")

print(response_object$url)
response_object <- self$request_sent |>
req_url_path_append(endpoint) |>
req_url_query(fields = ":all") |>
req_url_query(paging = "true") |>
req_url_query(pageSize = "1") |>
req_perform()

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)
message(response_object$url)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE)

sort(names(response_data[[2]]))
},
sort(names(response_data[[endpoint]]))
}else{
message("No internet connection!")
}
},
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' @description Get all possible analytics resources from a DHIS2 instance i.e
#'
Expand All @@ -244,48 +256,52 @@ Dhis2r <- R6::R6Class(
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

get_analytics= function(analytic,org_unit ,period, output_scheme= c("UID", "NAME")) {
# Check for internet
check_internet()
args <- list(analytic = analytic,org_unit= org_unit ,period = period, output_scheme = output_scheme)
#Check that at least one argument is not null

attempt::stop_if_any(args, is.null,"You need to specify all arguements")
attempt::stop_if_none(args, is.character, "All arguements should be type character")
if(has_internet()){

output_scheme <- match.arg(output_scheme)
# Check for internet

analytic <- paste0("dx:", paste0(analytic,collapse = ";"))
org_unit <- paste0("dimension=ou:", paste0(org_unit,collapse = ";"))
period <- paste0("dimension=pe:", paste0(period,collapse = ";"))
args <- list(analytic = analytic,org_unit= org_unit ,period = period, output_scheme = output_scheme)
#Check that at least one argument is not null

response_object <- self$request_sent |>
req_url_path_append("analytics") |>
req_url_query(dimension= I(paste(analytic, org_unit, period, sep = "&"))) |>
req_url_query(outputIdScheme = output_scheme) |>
req_perform()
attempt::stop_if_any(args, is.null,"You need to specify all arguements")
attempt::stop_if_none(args, is.character, "All arguements should be type character")

print(response_object$url)
output_scheme <- match.arg(output_scheme)

analytic <- paste0("dx:", paste0(analytic,collapse = ";"))
org_unit <- paste0("dimension=ou:", paste0(org_unit,collapse = ";"))
period <- paste0("dimension=pe:", paste0(period,collapse = ";"))

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE, flatten = TRUE)
response_object <- self$request_sent |>
req_url_path_append("analytics") |>
req_url_query(dimension= I(paste(analytic, org_unit, period, sep = "&"))) |>
req_url_query(outputIdScheme = output_scheme) |>
req_perform()

if(length(response_data$rows) == 0){
message(response_object$url)

as.data.frame(response_data$rows)

}else{
as.data.frame(response_data$rows) |>
setNames(c("analytic", "org_unit", "period", "value")) |>
tibble::as_tibble() |>
dplyr::mutate(analytic = as.factor(analytic),
org_unit = as.factor(org_unit),
value = as.numeric(value))
}
response_data <- response_object |>
resp_body_json(simplifyVector = TRUE, flatten = TRUE)

if(length(response_data$rows) == 0){

as.data.frame(response_data$rows)

},
}else{
as.data.frame(response_data$rows) |>
setNames(c("analytic", "org_unit", "period", "value")) |>
tibble::as_tibble() |>
dplyr::mutate(analytic = as.factor(analytic),
org_unit = as.factor(org_unit),
value = as.numeric(value))
}

}else{
message("No internet connection!")
}
},

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#' @description Get all any analytics resource from a DHIS2 instance to cater for long DHIS2 favorites
Expand All @@ -297,32 +313,37 @@ Dhis2r <- R6::R6Class(
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

get_any_analytic = function(endpoint_url) {
# Check for internet
check_internet()
args <- list(endpoint_url = endpoint_url)
#Check that at least one argument is not null

attempt::stop_if_any(args, is.null,"You need to specify all arguements")
attempt::stop_if_none(args, is.character, "All arguements should be type character")

if(has_internet()){

args <- list(endpoint_url = endpoint_url)
#Check that at least one argument is not null

attempt::stop_if_any(args, is.null,"You need to specify all arguements")
attempt::stop_if_none(args, is.character, "All arguements should be type character")


response_object <- self$request_sent |>
req_url_path_append(endpoint_url) |>
req_perform()
response_object <- self$request_sent |>
req_url_path_append(endpoint_url) |>
req_perform()

print(response_object$url)
message(response_object$url)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE, flatten = TRUE)

response_data <- response_object |>
resp_body_json(simplifyVector = TRUE, flatten = TRUE)
if(length(response_data$rows) == 0){

if(length(response_data$rows) == 0){
as.data.frame(response_data$rows)

as.data.frame(response_data$rows)
}else{
as.data.frame(response_data$rows) |>
tibble::as_tibble()
}

}else{
as.data.frame(response_data$rows) |>
tibble::as_tibble()
message("No internet connection!")
}
}
)
Expand Down
11 changes: 9 additions & 2 deletions R/utils.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#' @importFrom attempt stop_if_not
#' @importFrom attempt stop_if_not message_if_not
#' @importFrom curl has_internet
#' @import httr2
#' @import R6
check_internet <- function(){
stop_if_not(.x = has_internet(), msg = "Please check your internet connetion")
attempt::message_if_not(.x = has_internet(), msg = "Please check your internet connection")
}

#' Provide additional error information
#' @param resp response to be captured
#' @return An error character vector
#'
dhis2_error_message <- function(resp) {
resp_status_desc(resp)
}
3 changes: 3 additions & 0 deletions README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ knitr::opts_chunk$set(
[![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable)
[![R-CMD-check](https://github.com/amanyiraho/dhis2r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/amanyiraho/dhis2r/actions/workflows/R-CMD-check.yaml)
[![CRAN status](https://www.r-pkg.org/badges/version/dhis2r)](https://CRAN.R-project.org/package=dhis2r)
[![](https://cranlogs.r-pkg.org/badges/grand-total/dhis2r)](https://cranlogs.r-pkg.org/badges/grand-total/dhis2r)
[![](https://cranlogs.r-pkg.org/badges/dhis2r)](https://cran.r-project.org/package=dhis2r)

<!-- badges: end -->

## Overview
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://
[![R-CMD-check](https://github.com/amanyiraho/dhis2r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/amanyiraho/dhis2r/actions/workflows/R-CMD-check.yaml)
[![CRAN
status](https://www.r-pkg.org/badges/version/dhis2r)](https://CRAN.R-project.org/package=dhis2r)
[![](https://cranlogs.r-pkg.org/badges/grand-total/dhis2r)](https://cranlogs.r-pkg.org/badges/grand-total/dhis2r)
[![](https://cranlogs.r-pkg.org/badges/dhis2r)](https://cran.r-project.org/package=dhis2r)

<!-- badges: end -->

## Overview
Expand Down
10 changes: 9 additions & 1 deletion cran-comments.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

This is a resubmission. In this version I have:

* Updated the vignette to username and password instead of PAT since the public server is regularly updated
Updated the package to fail gracefully with an informative message if the resource is not available or has changed and doesn't give a check warning nor error. I have achieved this by making sure;

* API call functions print a massage "No internet connection!" if there is no internet connection instead of an error

* All examples run the if the environment is interactive and has internet

* All the tests are skipped on CRAN and are only run if there is an internet connection (Tests are always run during CI using github Actions)

* The vignettes are built using a mock up directory to that they can run without internet connection and when resources are unavailable


* I have tested the package on GITHUB actions and all past using these OSs
Expand Down
Loading

0 comments on commit 6586f1c

Please sign in to comment.