Access services specified in OpenAPI (formerly Swagger) format.
rapiclient is not a code generator. Client is generated dynamically as a list of R functions.
Install the current released version from CRAN:
install.packages("rapiclient")
Or get the current development version from github:
# install.packages("devtools")
devtools::install_github("bergant/rapiclient")
library(rapiclient)
This example uses the sample petstore service and its OpenAPI definition at (http://petstore.swagger.io/v2/swagger.json).
pet_api <- get_api(url = "http://petstore.swagger.io/v2/swagger.json")
operations <- get_operations(pet_api)
schemas <- get_schemas(pet_api)
Function get_operations
returns a list of functions.
Each function takes named arguments, converts the values to JSON
according to API operation definition and performs a service call which
returns a http response object.
Function get_schemas
returns a list of functions where each function returns
an object according to the related schema in the API.
Let's try to find a pet with Id = 42 (see operation definition):
res <- operations$getPetById(petId = 42)
res$status_code
# [1] 404
str(httr::content(res))
# List of 3
# $ code : int 1
# $ type : chr "error"
# $ message: chr "Pet not found"
OK, there is no pet with Id = 42, so let's add a pet:
res <-
operations$addPet(
id = 42,
category = schemas$Category(
id = 1,
name = "Undefined"
),
name = "Agrajag",
photoUrls = list(),
tags = list(
schemas$Tag(id = 1, name = "Wild"),
schemas$Tag(id = 2, name = "Furry")
),
status = "available"
)
res$status_code
# [1] 200
Check:
res <- operations$getPetById(petId = 42)
res$status_code
# [1] 200
str(httr::content(res))
# List of 6
# $ id : int 42
# $ category :List of 2
# ..$ id : int 1
# ..$ name: chr "Undefined"
# $ name : chr "Agrajag"
# $ photoUrls: list()
# $ tags :List of 2
# ..$ :List of 2
# .. ..$ id : int 1
# .. ..$ name: chr "Wild"
# ..$ :List of 2
# .. ..$ id : int 2
# .. ..$ name: chr "Furry"
# $ status : chr "available"
If all operations are handled identically (e.g. reading content or stop
on http exception), it is more convenient to create the API functions
with this functionality. get_operations
accepts an optional handler
function which must accept a httr response object as an argument.
Some handler functions are already predefined. For example content_or_stop
returns a content or throws an exception.
operations <- get_operations(pet_api, handle_response = content_or_stop)
pet_data <- operations$getPetById(42)
str(pet_data)
# List of 6
# $ id : int 42
# $ category :List of 2
# ..$ id : int 1
# ..$ name: chr "Undefined"
# $ name : chr "Agrajag"
# $ photoUrls: list()
# $ tags :List of 2
# ..$ :List of 2
# .. ..$ id : int 1
# .. ..$ name: chr "Wild"
# ..$ :List of 2
# .. ..$ id : int 2
# .. ..$ name: chr "Furry"
# $ status : chr "available"
Note that you can always trace the communication between client and server with httr::with_verbose
:
httr::with_verbose({
# get pet data
pet_data <- operations$getPetById(42)
# delete a pet entry
operations$deletePet(api_key = "special-key", petId = 42)
})
# NULL
# -> GET /v2/pet/42 HTTP/1.1
-> Host: petstore.swagger.io
-> User-Agent: libcurl/7.51.0 r-curl/2.3 httr/1.2.1
-> Accept-Encoding: gzip, deflate
-> Content-Type: application/json
-> Accept: application/json
->
<- HTTP/1.1 200 OK
<- Date: Tue, 14 Feb 2017 09:15:55 GMT
<- Access-Control-Allow-Origin: *
<- Access-Control-Allow-Methods: GET, POST, DELETE, PUT
<- Access-Control-Allow-Headers: Content-Type, api_key, Authorization
<- Content-Type: application/json
<- Connection: close
<- Server: Jetty(9.2.9.v20150224)
<-
-> DELETE /v2/pet/42 HTTP/1.1
-> Host: petstore.swagger.io
-> User-Agent: libcurl/7.51.0 r-curl/2.3 httr/1.2.1
-> Accept-Encoding: gzip, deflate
-> Content-Type: application/json
-> Accept: application/json
-> Content-Length: 0
->
<- HTTP/1.1 200 OK
<- Date: Tue, 14 Feb 2017 09:15:56 GMT
<- Access-Control-Allow-Origin: *
<- Access-Control-Allow-Methods: GET, POST, DELETE, PUT
<- Access-Control-Allow-Headers: Content-Type, api_key, Authorization
<- Content-Type: application/json
<- Connection: close
<- Server: Jetty(9.2.9.v20150224)
<-
The good news is that autocomplete in RStudio editor works fine with dynamically created functions. The bad news: R documentation is not available
with help
or ?
. To lookup the operation definition
just print the function (write it down without parenthesis):
Let's get help for getPetById
:
operations$getPetById
# getPetById
# Find pet by ID
# Description:
# Returns a single pet
#
# Parameters:
# petId (integer)
# ID of pet to return
More complicated addPet
also describes the nested schemas:
operations$addPet
# addPet
# Add a new pet to the store
#
# Parameters:
# id (integer)
# category (Category)
# name (string)
# photoUrls (array[string])
# tags (array[Tag])
# status (string)
# pet status in the store
# Category
# id (integer)
# name (string)
# Tag
# id (integer)
# name (string)
For more detailed operation description use the operation's "definition" attribute :
definition <- attr(operations$getPetById, "definition")
str(definition)
# List of 10
# $ tags : chr "pet"
# $ summary : chr "Find pet by ID"
# $ description: chr "Returns a single pet"
# $ operationId: chr "getPetById"
# $ produces : chr [1:2] "application/xml" "application/json"
# $ parameters :List of 1
# ..$ :List of 6
# .. ..$ name : chr "petId"
# .. ..$ in : chr "path"
# .. ..$ description: chr "ID of pet to return"
# .. ..$ required : logi TRUE
# .. ..$ type : chr "integer"
# .. ..$ format : chr "int64"
# $ responses :List of 3
# ..$ 200:List of 2
# .. ..$ description: chr "successful operation"
# .. ..$ schema :List of 1
# .. .. ..$ $ref: chr "#/definitions/Pet"
# ..$ 400:List of 1
# .. ..$ description: chr "Invalid ID supplied"
# ..$ 404:List of 1
# .. ..$ description: chr "Pet not found"
# $ security :List of 1
# ..$ :List of 1
# .. ..$ api_key: list()
# $ path : chr "/pet/{petId}"
# $ action : chr "get"
Set additional http headers at the time of creating operation functions
in get_operations
function.
The following example uses New York Times API from developer.nytimes.com with API key authentication.
nyt_api <- get_api("http://developer.nytimes.com/top_stories_v2.json/swagger.json")
nyt_operations <-
get_operations( nyt_api, .headers = c("api-key" = Sys.getenv("NYT_API_KEY")))
res <- nyt_operations$Top_Stories(section = "science", format = "json")
res$status_code
# [1] 200
content <- httr::content(res)
str(content, max.level = 1)
# List of 6
# $ status : chr "OK"
# $ copyright : chr "Copyright (c) 2017 The New York Times Company. All Rights Reserved."
# $ section : chr "science"
# $ last_updated: chr "2017-02-14T04:07:28-05:00"
# $ num_results : int 26
# $ results :List of 26