Выполнение POST-запроса для получения служебного билета внутри цикла for

#r #api #for-loop #http-post #httr

#r #API #for-цикл #http-post #httr

Вопрос:

Я работаю с REST API NIH / NLM и пытаюсь программно извлекать много данных одновременно. Я никогда не работал с API, который проверяет с помощью служебных билетов (TGT и ST) вместо OAUTH, которые необходимо обновлять для каждого запроса GET, который вы делаете, поэтому я не уверен, что я даже делаю это правильно. Любая помощь приветствуется.

Вот код, который у меня есть в настоящее время:

 library(httr)
library(jsonlite)
library(xml2)

UTS_API_KEY <- 'MY API KEY'

# post to the CAS endpoint
response <- POST('https://utslogin.nlm.nih.gov/cas/v1/api-key', encode='form', body=list(apikey = 'MY API KEY'))

# print out the status_code and content_type
status_code(response)
headers(response)$`content-type`

doc <- content(response)
action_uri <- xml_text(xml_find_first(doc, '//form/@action'))
action_uri

# Service Ticket
response <- POST(action_uri, encode='form', body=list(service = 'http://umlsks.nlm.nih.gov'))
ticket <- content(response, 'text')
ticket #this is the ST I need for every GET request I make


# build search_uri using the paste function for string concatenation
version <- 'current'
search_uri <- paste('https://uts-ws.nlm.nih.gov/rest/search/', version, sep='')

# pass the the query params into httr GET to get the response 
query_string <- 'diabetic foot'
response <- GET(search_uri, query=list(ticket=ticket, string=query_string))

## print out some of the results
search_uri
status_code(response)
headers(response)$`content-type`


search_results_auto_parsed <- content(response)
search_results_auto_parsed


class(search_results_auto_parsed$result$results)

search_results_data_frame <- fromJSON(content(response,'text'))
search_results_data_frame
  

Этот код отлично работает только для нескольких запросов GET, однако я пытаюсь извлечь 300 с чем-то медицинских терминов. Например, в строке запроса я хотел бы перебирать массив строк (например, «диабет», «кровяное давление», «сердечно-сосудистая помощь», «Скорая помощь» и т. Д.). Мне нужно было бы выполнить POST-запрос и передать ST в параметр GET для каждой строки в массиве.

Я поиграл с этим кодом:

 for (i in 1:length(Entity_Subset$Entities)){
  ent = Entity_Subset$Entities[i] #Entities represents my df of strings 
  url <- paste(' https://uts-ws.nlm.nih.gov/rest/search/current?string=',
               ent,'amp;ticket=', sep = "")
  print(url)
  }
  

Но мне не очень повезло собрать воедино запросы POST и GET после ввода строк в (GET) HTTPS-запрос.

Боковая панель: я также попытался написать несколько предварительных сценариев в Postman, но, как ни странно, служебный билет не возвращается как JSON (нет пары ключ-значение для захвата и передачи). Просто обычный текст.

Спасибо за любые советы, которые вы можете предоставить!

Комментарии:

1. Вы сказали, что POST-запрос необходим для каждого GET-запроса. Таким образом, каждый служебный билет предназначен только для одноразового использования, а не для повторного использования вообще?

2. @ekoam Точно. Только для одноразового использования и вообще не используется повторно. Это можно использовать повторно (в течение 5 минут), только если вы нажмете точно такой же запрос GET — почему, кто-нибудь захочет это сделать, я не уверен. Итак, в идеале, можно было бы встроить POST-запрос в какой-то цикл, который также проходит через массив строк для запроса GET?

Ответ №1:

Я думаю, вы можете просто обернуть оба запроса POST и GET в функцию. Затем lapply эта функция преобразуется в список символов.

 library(httr)
library(jsonlite)
library(xml2)

fetch_data <- function(query_string = 'diabetic foot', UTS_API_KEY = 'MY API KEY', version = 'current') {
  response <- POST('https://utslogin.nlm.nih.gov/cas/v1/api-key', encode='form', body=list(apikey = UTS_API_KEY))
  
  # print out the status_code and content_type
  message(status_code(response), "n", headers(response)$`content-type`)
  action_uri <- xml_text(xml_find_first(content(response), '//form/@action')); message(action_uri)
  
  # Service Ticket
  response <- POST(action_uri, encode = 'form', body=list(service = 'http://umlsks.nlm.nih.gov'))
  ticket <- content(response, 'text'); message(ticket)
  
  # build search_uri using the paste function for string concatenation
  search_uri <- paste0('https://uts-ws.nlm.nih.gov/rest/search/', version)
  # pass the the query params into httr GET to get the response 
  response <- GET(search_uri, query=list(ticket=ticket, string=query_string))
  ## print out some of the results
  message(search_uri, "n", status_code(response), "n", headers(response)$`content-type`)
  fromJSON(content(response, 'text'))
}

# if you have a list of query strings, then
lapply(Entity_Subset$Entities, fetch_data, UTS_API_KEY = "blah blah blah")

# The `lapply` above is logically equivalent to
result <- vector("list", length(Entity_Subset$Entities))
for (x in Entity_Subset$Entities) {
  result[[x]] <- fetch_data(x, "blah blah blah")
}
  

Комментарии:

1. Большое вам спасибо! Это абсолютно сработало. И спасибо за подробное объяснение.