Search code examples
rjsonhttr

Querying a server with R based on a Python example


I am trying to convert the following Python script in R:

import pandas as pd
import requests
import json
url = "https://telraam-api.net/v1/reports/traffic"
body = {
    "id":"9000001463",
    "time_start":"2022-10-01 00:00:00Z",
    "time_end":"2022-10-02 00:00:00Z",
    "level":"segments",
    "format":"per-hour"
}
headers = {
  'X-Api-Key': '***My_API-Key***'
}
payload = str(body)
response = requests.request("POST", url, headers=headers, data=payload)
json = response.json()
dataframe = pd.DataFrame(json['report'])
dataframe.to_csv('test.csv')

where My_API-Key stands for my API key which I cannot communicate.

I used the following:

get_telraam_data <- function(id = "9000001463",
                       time_start = "2022-10-01 00:00:00Z",
                       time_end = "2022-10-02 00:00:00Z",
                       level = "segments",
                       format = "per-hour",
                       token = "***My_API-Key***") {
  GET(
    url = sprintf("https://telraam-api.net/v1"),
    query = list(
      id = id,
      time_start = time_start,
      time_end = time_end,
      level = level,
      format = format
    ),
    content_type_json(),
    add_headers("X-Api-Key" = token)
  ) -> res

  stop_for_status(res)

  content(res, as="text", encoding="UTF-8") %>%
    fromJSON(flatten=TRUE) %>%
    as_tibble() %>%
    readr::type_convert()
}

but the query does not seem to work.

Where did I make an error? Is body a query?


Solution

  • requests.request("POST", ...) is a POST call while httr example is using GET. You can compare requests / responses by making calls to some testing service, e.g. http://httpbin.org/ . Or just open up a socket on your own machine to see how requests differ. With httr, this should do:

    library(httr)
    
    id         <- "9000001463"
    time_start <- "2022-10-01 00:00:00Z"
    time_end   <- "2022-10-02 00:00:00Z"
    level      <- "segments"
    format     <- "per-hour"
    token      <- "***My_API-Key***"
    
    api_endpoint <- "https://httpbin.org/post"
    # or just run netcat on your own host to check the request:
    # nc -l 1234
    #api_endpoint <- "http://localhost:1234"
    
    POST(
      url = api_endpoint,
      body = list(
        id = id,
        time_start = time_start,
        time_end = time_end,
        level = level,
        format = format
      ),
      encode = "json",
      content_type_json(),
      add_headers("X-Api-Key" = token)
    )
    #> Response [https://httpbin.org/post]
    #>   Date: 2023-05-28 19:15
    #>   Status: 200
    #>   Content-Type: application/json
    #>   Size: 851 B
    #> {
    #>   "args": {}, 
    #>   "data": "{\"id\":\"9000001463\",\"time_start\":\"2022-10-01 00:00:00Z\",\"t...
    #>   "files": {}, 
    #>   "form": {}, 
    #>   "headers": {
    #>     "Accept": "application/json, text/xml, application/xml, */*", 
    #>     "Accept-Encoding": "deflate, gzip", 
    #>     "Content-Length": "128", 
    #>     "Content-Type": "application/json", 
    #> ...
    

    Though I'd personally use httr2:

    library(dplyr)
    library(httr2)
    response <-  request(api_endpoint) %>% 
      req_headers("X-Api-Key" = token) %>% 
      req_body_json(list(
        id = id,
        time_start = time_start,
        time_end = time_end,
        level = level,
        format = format)) %>% 
      # to check request without actually sending it:
      # req_dry_run()
      req_perform(verbosity = 2) %>% 
      resp_body_json(simplifyVector = TRUE) 
    #> -> POST /post HTTP/1.1
    #> -> Host: httpbin.org
    #> -> User-Agent: httr2/0.2.2 r-curl/5.0.0 libcurl/7.84.0
    #> -> Accept: */*
    #> -> Accept-Encoding: deflate, gzip
    #> -> X-Api-Key: ***My_API-Key***
    #> -> Content-Type: application/json
    #> -> Content-Length: 128
    #> -> 
    #> >> {"id":"9000001463","time_start":"2022-10-01 00:00:00Z","time_end":"2022-10-02 00:00:00Z","level":"segments","format":"per-hour"}
    #> <- HTTP/1.1 200 OK
    #> <- Date: Sun, 28 May 2023 19:15:26 GMT
    #> <- Content-Type: application/json
    #> <- Content-Length: 807
    #> <- Connection: keep-alive
    #> <- Server: gunicorn/19.9.0
    #> <- Access-Control-Allow-Origin: *
    #> <- Access-Control-Allow-Credentials: true
    #> <- 
    #> << {
    #> <<   "args": {}, 
    #> <<   "data": "{\"id\":\"9000001463\",\"time_start\":\"2022-10-01 00:00:00Z\",\"time_end\":\"2022-10-02 00:00:00Z\",\"level\":\"segments\",\"format\":\"per-hour\"}", 
    #> <<   "files": {}, 
    #> <<   "form": {}, 
    #> <<   "headers": {
    #> <<     "Accept": "*/*", 
    #> <<     "Accept-Encoding": "deflate, gzip", 
    #> <<     "Content-Length": "128", 
    #> <<     "Content-Type": "application/json", 
    #> <<     "Host": "httpbin.org", 
    #> <<     "User-Agent": "httr2/0.2.2 r-curl/5.0.0 libcurl/7.84.0", 
    #> <<     "X-Amzn-Trace-Id": "Root=1-6473a84e-5ed51b7c52cac4ce2a19f855", 
    #> <<     "X-Api-Key": "***My_API-Key***"
    #> <<   }, 
    #> <<   "json": {
    #> <<     "format": "per-hour", 
    #> <<     "id": "9000001463", 
    #> <<     "level": "segments", 
    #> <<     "time_end": "2022-10-02 00:00:00Z", 
    #> <<     "time_start": "2022-10-01 00:00:00Z"
    #> <<   }, 
    #> <<   "origin": "91.101.104.191", 
    #> <<   "url": "https://httpbin.org/post"
    #> << }
    

    Created on 2023-05-28 with reprex v2.0.2