PoliticaArgentina / geoAr

🌎 🇦🇷 spatial toolbox for R
https://politicaargentina.github.io/geoAr/
Other
15 stars 2 forks source link

consultas POST de georef API #13

Open jgjuara opened 1 year ago

jgjuara commented 1 year ago

Sería conveniente agregar funciones que faciliten las consultas por método POST a la API de georef-ar como mencionó @gonzaloazuaga2021 en https://github.com/PoliticaArgentina/geoAr/issues/12#issuecomment-1607489921_

jgjuara commented 1 year ago

basandome en el codigo para GET propongo:


base_url <- "http://apis.datos.gob.ar/georef/api/"

post_endpoint <- function(endpoint, args) {

  # Obtener el token de la variable de entorno
  token <- Sys.getenv("GEOREFAR_TOKEN")

  url <- paste0(base_url, endpoint)

  load <- as.data.frame(x = args) %>%
    list() %>%
    setNames(., endpoint)

  body <- jsonlite::toJSON(load, auto_unbox = T)

  # Comprobar si el token está presente
  if (is.null(token) | token == "") {
    response <- httr::POST(url, body = body,
                           encode = "raw",
                           httr::add_headers("Content-Type" = "application/json")
                           )

  } else {
    response <- httr::POST(url, body = body,
                           encode = "raw",
                           httr::add_headers(Authorization = paste("Bearer",
                                                                   token),
                                             "Content-Type" = "application/json"))
  }

  check_status(response)

  jsonlite::fromJSON(httr::content(response, "text"))[["resultados"]][endpoint] %>%
    tidyr::unnest(cols = c(calles)) %>%
    jsonlite::flatten(recursive = T) %>%
    dplyr::rename_with(.fn = function(x) {gsub(pattern = "\\$|\\.", replacement = "_", x = x)}) %>%
    suppressMessages()
}

#' Obtener Calles

post_calles <- function(id = NULL, nombre = NULL, tipo = NULL, provincia = NULL, departamento = NULL, aplanar = TRUE, campos = NULL, max = NULL, exacto = NULL){

  args <- purrr::compact(list(id = id, nombre = nombre, tipo = tipo, provincia = provincia, departamento = departamento, aplanar = aplanar, campos = campos, max = max, exacto = exacto))

  endpoint <- "calles"

  check_internet()

  post_endpoint(endpoint = endpoint, args = args)

}
jgjuara commented 1 year ago

@TuQmano @pdelboca estaba pensando que en vez de armar toda una nueva tanda de funciones post_* quizás es mejor hacer una función buscar_* que tenga una parametro para el método POST/GET. En vez de:

get_localidades(...) 
post_localidades(...) 

Tener:

buscar_localidades(metodo = "GET", ...)
buscar_localidades(metodo = "POST", ...)

¿qué les parece?

TuQmano commented 1 year ago

A mi me gusta. Ver de no agregar muchas mas funciones exportables y que cada endpoint tenga un par segun param que defina el metodo. Ahi surgiría una decision:

jgjuara commented 1 year ago
base_url <- "http://apis.datos.gob.ar/georef/api/"

get_endpoint <- function(endpoint, args) {

  if (! assertthat::noNA(args)) {
    stop(c('GET no admite NAs. Los parametros siguientes tienen NAs:', sapply(names(args[is.na(args)]),
                                                          function(x) paste0(" ", x),
                                                          USE.NAMES = F)))
  }

  # Obtener el token de la variable de entorno
  token <- Sys.getenv("GEOREFAR_TOKEN")

  url <- paste0(base_url, endpoint)

  # Comprobar si el token esta presente
  if (is.null(token) | token == "") {
    response <- httr::GET(url, query = args)
  } else {
    response <- httr::GET(url,
                          httr::add_headers(Authorization = paste("Bearer", token)),
                          query =  args)
  }

  parsed <- suppressMessages(jsonlite::fromJSON(httr::content(response, "text")))

  check_status(response)

  data <- parsed[[gsub(pattern = "-",replacement = "_", x = endpoint)]] %>%
    purrr::modify_if(is.null, list)

  if (length(data) == 0) {
    warning("La consulta devolvio una lista vacia", call. = F)
  }

  data %>%
    dplyr::as_tibble(.name_repair = function(x) {gsub(pattern = "\\$|\\.", replacement = "_", x = x)})
}

post_endpoint <- function(endpoint, args, drop_params) {

  # if (! assertthat::noNA(unlist(args))) {
  #   stop(c('Los parametros siguientes tienen NAs:',
  #          sapply(filter(.data = as_tibble(apply(sapply(args, is.na),
  #                                                MARGIN = 2, FUN = sum),
  #                                          rownames = "parametros"), value != 0)$parametros,
  #          function(x) paste0(" ", x), USE.NAMES = F)))
  #        }

  # Obtener el token de la variable de entorno
  token <- Sys.getenv("GEOREFAR_TOKEN")

  url <- paste0(base_url, endpoint)

  args <- discard(args, is.null)

  load <- as.data.frame(x = args) %>%
    list() %>%
    setNames(., endpoint)

  body <- jsonlite::toJSON(load)

  # Comprobar si el token está presente
  if (is.null(token) | token == "") {
    response <- httr::POST(url, body = body,
                           content_type_json()
    )

  } else {
    response <- httr::POST(url, body = body,
                           encode = "raw",
                           httr::add_headers(Authorization = paste("Bearer",
                                                                   token),
                                             "Content-Type" = "application/json"))
  }

  parsed <- jsonlite::fromJSON(httr::content(response, "text"))

  check_status(response)

  data <- parsed[["resultados"]][c(endpoint, "parametros")] %>%
    tidyr::unnest(cols = dplyr::all_of(endpoint), keep_empty = T) %>%
    jsonlite::flatten(recursive = T) %>%
    dplyr::rename_with(.fn = function(x) {gsub(pattern = "\\$|\\.", replacement = "_", x = x)}) %>%
    suppressMessages()

  if (nrow(filter(data, if_all(.cols =  !matches("parametros"), .fns = is.na))) != 0) {
    warning("La consulta una o mas respuestas vacias", call. = F)
  }

  if (drop_params) {
    data %>% select(-matches("parametros"))
  } else {
    data
  }
}

#' Consultar Calles
consultar_calles <- function(id = NULL, nombre = NULL, tipo = NULL, provincia = NULL, departamento = NULL, aplanar = TRUE, campos = NULL, max = NULL, exacto = NULL,  drop_params = T, post = F){

  assertthat::assert_that(is.logical(post), msg = "parametro 'post' debe ser logico")
  assertthat::assert_that(is.logical(drop_params), msg = "parametro 'drop_params' debe ser logico")
  assertthat::assert_that(max <= 5000 || is.null(max), msg = "parametro 'max' debe ser menor a 5000 o NULL")

  args <- list(id = id, nombre = nombre, tipo = tipo, provincia = provincia, departamento = departamento, aplanar = aplanar, campos = campos, max = max, exacto = exacto)

  endpoint <- "calles"

  check_internet()

  if (post) {
    post_endpoint(endpoint = endpoint, args = args, drop_params = drop_params)
  } else {
    get_endpoint(endpoint = endpoint, args = args)
  }

}