0
votes

I'm having a problem connecting R to an application's REST API.

I can call commands from the REST API using the RCurl package's getURL function as follows, and it works nicely.

RESTQuery = paste0(MyBaseURL,MyRESTQuery)
RESTHeader = c(
    paste0("Host:",MyServerIP,":",MyServerPort),
    paste0("Authorization:Basic ",MyEncodedToken),
    "Connection: keep-alive"
)
RESTResult = getURL(URL=RESTQuery,httpheader=RESTHeader,verbose=true)

This RESTResult can then be parsed with the fromJSON(RESTResult) and it works great.

However, I couldn't find the equivalent way to send POST RCurl requests with the header included, so I moved to the httr package to send the POST requests. The following code works, but the fromJSON function returns an error:

RESTQuery = paste0(MyBaseURL,MyRESTQuery)
RESTPOSTHeader = c(
    'Content-Type'="application/json; charset=utf-8",
    'Authorization'=paste0("Basic ",MyEncodedToken),
    'Accept'="application/json"
)
RESTPOSTBody = c(
    "$expand=Axes,Cells"
)
RESTResult <- POST(RESTQuery,query=RESTPOSTBody,add_headers(RESTPOSTHeader),verbose())

The returned values are correctly returned from the REST API but they don't appear to be formatted as JSON, and so I can't parse them into a nice dataframe. Here is the returned code from the query in verbose mode:

-> User-Agent: curl/7.39.0 Rcurl/1.95.4.5 httr/0.6.1
-> Host: <My server>:<My Port>
-> Accept-Encoding: gzip
-> Cookie: SessionId=NMD-MavwPL_QhdHFMRyhZQ
-> Content-Type: application/json; charset=utf-8
-> Authorization: Basic <My Encoded Token>
-> Accept: application/json
-> Content-Length: 0
-> 
<- HTTP/1.1 201 Created
<- Content-Length: 944
<- Connection: keep-alive
<- Content-Encoding: gzip
<- Cache: no-cache
<- Content-Type: application/json;odata.metadata=minimal;odata.streaming=true; charset=utf-8
<- Location: ../../Cellsets('sIYzNM4HAIAGAAAg')
<- OData-Version: 4.0
<- Set-Cookie: SessionId=7V5XAXXjwfbaXmdOb3FgJQ; Path=/api/; HttpOnly

And the values when I use content(RESTResult):

> content(RESTResult)
$`@odata.context`
[1] "../../$metadata#Cellsets(Axes(Hierarchies+(Name),Tuples+(Members(Name))),Cells)/$entity"

$ID
[1] "sIYzNM4HAIAGAAAg"
$Axes
$Axes[[1]]
$Axes[[1]]$Ordinal
[1] 0
$Axes[[1]]$Cardinality
[1] 3
$Axes[[1]]$Hierarchies
$Axes[[1]]$Hierarchies[[1]]
$Axes[[1]]$Hierarchies[[1]]$Name
[1] "Period_General"
$Axes[[1]]$Tuples
$Axes[[1]]$Tuples[[1]]
$Axes[[1]]$Tuples[[1]]$Ordinal
[1] 0
$Axes[[1]]$Tuples[[1]]$Members
$Axes[[1]]$Tuples[[1]]$Members[[1]]
$Axes[[1]]$Tuples[[1]]$Members[[1]]$Name
[1] "all periods"

$Cells
etc.............

When I try to format that using fromJSON I get error "Argument 'txt' must be a JSON string, URL or File" if I try any of the following:

  • fromJSON(RESTResult)
  • fromJSON(content(RESTResult))
  • fromJSON(content(RESTResult)$Cells)

So, I'm a bit stuck on the following:

  1. How to send the POST request using the RCurl package or
  2. How to retrieve proper JSON results from a REST API using the HTTR package POST command?

Am I setting headers wrong, or doing something incredibly stupid? Any advice would be great! Thanks!!

1
Am I wrong that the output of content(RESTResult) is what you want, but it's already been parsed? That is, if you wanted to loop over the "Axes" in the results, you'd do for (axis in content(RESTResult)$Axes) {.... - David Robinson
If you wanted to get JSON, you could do j <- toJSON(content(RESTResult)), and then fromJSON(j). But that would just be turning it right into JSON and then turning it back! - David Robinson
The reason I thought it was a bit strange is that the results I was getting back from the getURL query were formatted very nicely, but maybe you're right, and there is some parsing already being done! It would also be cool to learn how to do this with the RCurl package, just so I can do a direct comparison but whatever I try, I can not get the RCurl package to work with my POST requests. - Deef
I'd recommend httr over RCurl in general, it provides more options and a more powerful interface. But if you want to get the text output with that formatting, try content(RESTResult, type = "text"). - David Robinson
Thanks David, I'll give that a try! I'm going to try that and I'll come back if I don't get something! - Deef

1 Answers

0
votes

This has now been solved, thanks to help from David Robinson in the comments to my original question.

To solve the issue, and use the formatted result from the fromJSON() function, parse the result from the query as text, then use the fromJSON function.

RESTResult <- POST(RESTQuery,query=RESTPOSTBody,add_headers(RESTPOSTHeader),verbose())
RESTResultParsed <- fromJSON(content(RESTResult,type="text"))

The result is a very nice list, which you can then manipulate using the standard functions.