Table of contents
TOC
Collapse the table of content
Expand the table of content

Working with web services in R

j-martens|Last Updated: 2/24/2017

This article describes how you can interact with and manage analytic web services directly in R using functions in the mrsdeploy package. This R package is installed with both Microsoft R Client and Microsoft R Server. Note that a set of RESTful APIs are also available to provide direct programmatic access to a service's lifecycle directly.

Using mrsdeploy with a properly configured R Server allows you to publish R functions (models, R scripts, arbitrary R code) exposed as analytic web services in as little as a single line of R code. A web service might contain not only the model, but also the prediction script used to create it.

Once hosted in R Server, these web services can be discovered by other authenticated users. These users can consume the web services in R or in the language of their choice via Swagger.

Permissions and function descriptions

In addition to the authentication functions, the following functions are used to bundle R code or R scripts as web services.

Important

To use the functions in the mrsdeploy package, you must log into R Server as an authenticated user. Learn about the login/logout functions and their arguments in the article "Connecting to R Server to use mrsdeploy".

Any authenticated user can publish an analytic web service to a given R Server instance. They can also retrieve a list of the available services hosted in R Server as well as retrieve service objects from them for consumption them regardless of whether they published those services or not.

In this release, you can only manage (update/delete) the web services you've published. You cannot manage the services published by other users.

Web service functionsDescriptionYour ServiceOther Services
publishServicePublishes R code as a web service on R Server.YesN/A
updateServiceUpdates an existing web service on an R Server instance.YesNo
deleteServiceDeletes a web service on an R Server instance.YesNo
listServicesReturns a list of published web services on the R Server instance.YesYes
getServiceReturns a web service object for consumption.YesYes

Publish and manage in R

Publish web services

In order to deploy your analytics, you must publish them as new web services running on R Server. Each service is uniquely defined by a name and version. Additionally, each web service includes the R code and any necessary model assets, the required inputs, and the output application developers will need to integrate in their applications.

The mrsdeploy function for publishing as web services is publishService.

FunctionResponse
publishService(...)Returns an API instance (client stub for consuming that service and viewing its service holdings) as an R6 class.

From your local commandline, you can publish web services to a local R Server or remotely if you set up a remote session.

Important

In the case where you are working with a remote R session, keep in mind that you can only publish from the local session. If you attempt to publish remotely, it will fail with this message: Error in curl::curl_fetch_memory(uri, handle = h) : URL using bad/illegal format or missing URL. If you are in your remote session, switch back to the local commandline to publish your service.

The following arguments are accepted for publishService:

ArgumentsDescription
name *The unique web service name. It is a string so use quotes such as "MyService". We recommend that you use a name that is easy understood and fits a nice URL so people can remember it.
code *R code to publish. If you use a path, the base path is your local current working directory. code can take the form of:
1. A filepath to a local R script. For example:
    code = "/path/to/R/script.R"
2. A block of R code as a character string. For example:
    code = "result <- x + y"
3. A function handle. For example:
    code = function(hp, wt) {
         newdata <- data.frame(hp = hp, wt = wt)
         predict(model, newdata, type = "response")
      }
modelAn object or a file-path to an external representation of R objects to be loaded and used with code. The specified file can be:
1. File-path to a local .RData file holding R objects to be loaded. For example:
    model = "/path/to/glm-model.RData"
2. File-path to a local .R file which will be evaluated into an environment and loaded. For example:
    model = "/path/to/glm-model.R"
3. An object. For example:
    model = am.glm
snapshotIdentifier of the snapshot to load. Can replace the model argument or be merged with it.
inputsDefines the web service input schema. If empty, the service will not accept inputs. inputs are defined as a named list list(x = "logical") which describe the input parameter names and their corresponding data types.
outputsDefines the web service output schema. If empty, the service will not return a response value. outputs are defined as a named list list(x = "logical") which describe the output parameter names and their corresponding Data Types
Note: If {code} is defined as a {function} then only one output value can be claimed.
vDefines a unique alphanumeric web service version. If the version is left blank, a unique {guid} will be generated in its place. Useful during service development before the author is ready to officially publish a semantic version to share. Learn more...
aliasAn alias name of the predication remote procedure call (RPC) function used to consume the service. If code is a function, it will use that function name by default. See Api.
destinationThe codegen output directory location.
descrThe description of the web service.

* If an argument is marked with an asterisk (*), then the argument is required by the function.

Example

See full examples in the "Workflow" examples at the end of this article.

# Publish web service called mtService and 
# assign version number v1.0.0
api <- publishService(
     "mtService",
     code = manualTransmission,
     model = carsModel,
     inputs = list(hp = "numeric", wt = "numeric"),
     outputs = list(answer = "numeric"),
     v = "v1.0.0"
)

I/O data types

The following table lists the supported data types for the publishService and updateService function input and output schemas:

I/O data types:numericintegerlogicalcharactervectormatrixdata.frame
Full Support



Yes



Yes



Yes



Yes



Yes



Some.
(Not logical & character matrices)
Yes
Note: Coercing an object during I/O is a user-defined task

Version web services

Every time a web service is published, a version is assigned to the web service. Versioning enables users' publishing services to better manage the release of their services and for those users consuming the services to more easily identify what they are calling.

When publishing, you can specify a version. If you forget to assign one, one is generated for you.

  • To specify a version, use any alphanumeric string that is meaningful to those who will consume the service in your organization, such as 2.0, v1.0.0, v1.0.0-alpha, v1.0.0-test, test-1. Meaningful versions are very helpful when you are ready to share your services with others. We highly recommend that everyone in your organization use a consistent and meaningful versioning convention such as semantic versioning when publishing services.

  • If you do not specify a version, a globally unique identifier (GUID) is automatically assigned by R Server as a unique reference number. These GUID version numbers are harder to remember for those consuming your services, so they are not popular.

Update web services

If you want to change your web service after you've published it, but keep the same name and version, you can use updateService. and specify what needs to change, such as the R code, model, inputs, and so on. You can change one or more of the arguments at the same time. When you update a service, it overwrites that named version.

Note

If you want to change the name or version number, use the publishService function instead and specify the new name or version number.

The mrsdeploy function for updating as web services is updateService.

FunctionResponse
updateService(...)Returns an API instance (client stub for consuming that service and viewing its service holdings) as an R6 class.

The following arguments are accepted for updateService:

ArgumentsDescription
name*The web service name you want to update. It is a string so use quotes such as "MyService".
v*Identifies the version of the web service to be updated.
codeR code to publish. If you use a path, the base path is your local current working directory. code can take the form of:
1. A filepath to a local R script. For example:
    code = "/path/to/R/script.R"
2. A block of R code as a character string. For example:
    code = "result <- x + y"
3. A function handle. For example:
    code = function(hp, wt) {
         newdata <- data.frame(hp = hp, wt = wt)
         predict(model, newdata, type = "response")
      }
modelAn object or a file-path to an external representation of R objects to be loaded and used with code. The specified file can be:
1. File-path to a local .RData file holding R objects to be loaded. For example:
    model = "/path/to/glm-model.RData"
2. File-path to a local .R file which will be evaluated into an environment and loaded. For example:
    model = "/path/to/glm-model.R"
3. An object. For example:
    model = am.glm
snapshotIdentifier of the snapshot to load. Can replace the model argument or be merged with it.
inputsDefines the web service input schema. If empty, the service will not accept inputs. inputs are defined as a named list list(x = "logical") which describe the input parameter names and their corresponding data types.
outputsDefines the web service output schema. If empty, the service will not return a response value. outputs are defined as a named list list(x = "logical") which describe the output parameter names and their corresponding Data Types
Note: If {code} is defined as a {function} then only one output value can be claimed.
aliasAn alias name of the predication remote procedure call (RPC) function used to consume the service. If code is a function, it will use that function name by default. See Api.
destinationThe codegen output directory location.
descrThe description of the web service.

* If an argument is marked with an asterisk (*), then the argument is required by the function.

For more information on input and output data types, see the above section I/O Data Types.

Example

# For web service called mtService with version number v1.0.0,
# update the model carsModel, code, inputs, and description. 
# Assign it to a variable called api.
api <- updateService(
     "mtService",
     "v1.0.0",
     code = manualTransmission,
     mode = carsModel,
     inputs = list(wt = "numeric", dist = "numeric")
     descr = "Updated after March data refresh."
)

Delete web services

When you no longer want to keep a web service, you can delete it. Only the user who initially created the web service can use this function.

The mrsdeploy function for deleting a web services is deleteService.

FunctionResponse
deleteService(...)If it is successful, it returns a success status and message such as "Service mtService version v1.0.0 deleted.". If it fails for any reason, then it stops execution with error message.

The following arguments are accepted for deleteService:

ArgumentsDescription
name*The web service name you want to delete. It is a string so use quotes such as "MyService".
v*Identifies the version of the web service to be deleted.

* If an argument is marked with an asterisk (*), then the argument is required by the function.

Example

result <- deleteService("mtService", "v1.0.0")
print(result)

Interact with services in R

List web services

Any authenticated user can retrieve a list of web services using the listServices function. You can use arguments to restrict the list to return a specific web service or all labeled versions of a given web service.

The mrsdeploy function for listing available web services is listServices.

FunctionResponse
listServices(...)R list containing service metadata.

The following arguments are accepted for listServices:

ArgumentsDescription
nameWhen specified, will return only web services with that name. It is a string so use quotes such as "MyService".
vWhen specified, will return only web services with that name and specific version number.

* If an argument is marked with an asterisk (*), then the argument is required by the function.

Example

# Return metadata for all services hosted on this R Server
allServices <- listServices()

# Return metadata for every version of the 
# service "mtService" hosted on this R Server
mtServiceAll <- listServices("mtService")

# Return metadata for version v1.0.0 of the 
# service "mtService" hosted on this R Server
mtServiceV1 <- listServices("mtService", "v1")

# View service capabilities/schema. 
# For example, the input schema:
#   list(name = "wt", type = "numeric")
#   list(name = "dist", type = "numeric")
print(mtService)

This example returns:

$creationTime
[1] "2017-02-13T19:44:26.2611422"

$name
[1] "mtService"

$version
[1] "v1"

$description
NULL

$snapshotId
[1] "05053e85-c9d0-43cb-9be8-8dccf2b5da54"

$owner
[1] "rserver-user"

$inputParameterDefinitions
$inputParameterDefinitions[[1]]
$inputParameterDefinitions[[1]]$name
[1] "hp"

$inputParameterDefinitions[[1]]$type
[1] "numeric"

$inputParameterDefinitions[[2]]
$inputParameterDefinitions[[2]]$name
[1] "wt"

$inputParameterDefinitions[[2]]$type
[1] "numeric"

$outputParameterDefinitions
$outputParameterDefinitions[[1]]
$outputParameterDefinitions[[1]]$name
[1] "answer"

$outputParameterDefinitions[[1]]$type
[1] "numeric"

$operationId
manualTransmission

Retrieve service objects

Any authenticated user can retrieve a web service object using the getService function that makes it possible for the service to be consumed. Once the object is returned, you can look at its capabilities to see what the service can do and how it should be consumed.

The mrsdeploy function for retrieving a service object is getService.

FunctionResponse
getService(...)Returns an API instance (client stub for consuming that service and viewing its service holdings) as an R6 class.

The following arguments are accepted for getService:

ArgumentsDescription
name*The name of the web service whose object you want to retrieve. It is a string so use quotes such as "MyService".
v*The version of the web service whose object you want to retrieve.

* If an argument is marked with an asterisk (*), then the argument is required by the function.

Example

# Get service using `getService()` function from `mrsdeploy` package.
# Assign service to the variable `api`.
api <- getService("mtService", "v1.0.0")

# Print capabilities to see what service can do.
print(api$capabilities())

# Start interacting with the service, for example:
# Calling the function, `manualTransmission`
# contained in this service.
result <- api$manualTransmission(120, 2.8)

Interact with API clients

When you publish, update or get a web service, an API instance is returned as an R6 class. This instance is a client stub for consuming that service and viewing its service holdings.

You can use the following supported public functions to interact with the API client instance.

Supported public functions

FunctionDescription
printPrint method that lists all members of the object
capabilitiesReport on the service features such as I/O schema, name, version
consumeConsume the service based on I/O schema
consume aliasAlias to the consume function for convenience (see alias argument for the publishService function).
swaggerDisplays the service's swagger specification

Example

# Get service using `getService()` function from `mrsdeploy`.
# Assign service to the variable `api`
api <- getService("mtService", "v1.0.0")

# Print capabilities to see what service can do.
print(api)

# Print the service name, version, inputs, outputs, and the
# Swagger-based JSON file used to consume the service 
cap <- api$capabilities()
print(cap$name)
print(cap$version)
print(cap$inputs)
print(cap$outputs)
print(cap$swagger)

# Start interacting with the service by calling it with the
# generic name `consume` based on I/O schema
result <- api$consume(120, 2.8)

# Or, start interacting with the service using the alias argument
# that was defined at publication time.
result <- api$manualTransmission(120, 2.8)

# Since you're authenticated, get this service's `swagger.json`.
swagger <- api$swagger(json = FALSE)
cat(swagger)

Consume web services

Once a web service has been published, it can be consumed. Whenever the web service is published or updated, a Swagger-based JSON file is generated automatically to define the service to facilitate consumption and integration.

When you publish a service, you should let people know that is ready for them to try out. There are several ways for users to consume services. If you do not provide them with a service name or version, they can discover the service on their own using the listServices function described earlier in this article.

Collaborate with data scientists

Other data scientist may want to explore, test, and consume Web services directly in R using the functions in the mrsdeploy package installed with Microsoft R Server and R Client. Quality engineers might want to bring the models in these web services into validation and monitoring cycles.

As the owner of the service, you can share the name and version number for the service with fellow data scientists so they can call the service in R using the functions in the mrsdeploy package. After authenticating, data scientists can use the getService function in R to call the service. Then, they can get details about the service and start consuming it.

##########################################################
#        Get Swagger File for Service in R Later         #
##########################################################

# Use `remoteLogin` to authenticate with R Server using 
# the local admin account. Use session = false so no 
# remote R session started
remoteLogin("http://localhost:12800", 
            username = “admin”, 
            password = “{{YOUR_PASSWORD}}”,
            session = FALSE)

# Get service using `getService()` function from `mrsdeploy`
# Assign service to the variable `api`.
api <- getService("mtService", "v1.0.0")

# Print capabilities to see what service can do.
print(api$capabilities())

# Start interacting with the service, for example:
# Calling the function, `manualTransmission`
# contained in this service.
result <- api$manualTransmission(120, 2.8)

# Print response output named `answer`
print(result$output("answer")) # 0.6418125  

# Since you're authenticated now, get `swagger.json`.
swagger <- api$swagger()
cat(swagger, file = "swagger.json", append = FALSE)

Collaborate with application developers

Application developers can call and integrate web services into their applications using each service-specific Swagger-based JSON file along with the required inputs.

Once the application developer has this Swagger-based JSON file, he or she can create client libraries for integration. Read "Application Developer Get Started Guide" for more details.

Get the Swagger-based JSON file in one of two ways:

  • A data scientist can send them the Swagger-based JSON file they've downloaded, which can sometimes be a faster approach. In R, you can get the file with the following code and send it to the application developer:

     api <- getService("<name>", "<version>")
     swagger <- api$swagger()
     cat(swagger, file = "swagger.json", append = FALSE)
    
  • Or, the application developer can request the file as an authenticated user with an active bearer token in the request header (since all API calls must be authenticated). The URL is formed as follows:

    GET /api/<service-name>/<service-version>/swagger.json
    

Workflows: publish-to-consume

The following workflow examples demonstrate how to publish a web service, interact with it, and consume it.

In each example, the values of the R code (code) and the model (model) are represented in different ways (as files, objects, ...), but in each case the result is the same.

Remember that R code can come from:

  1. A filepath to a local R script, such as: code = "/path/to/R/script.R"
  2. A block of R code as a character string, such as: code = "result <- x + y"
  3. A function handle, such as:
        code = function(hp, wt) {
             newdata <- data.frame(hp = hp, wt = wt)
             predict(model, newdata, type = "response")
          }

Similarly, a model can come from an object or a file-path to an external representation of R objects to be loaded and used with code:

  1. File path to an .RData file holding R objects to be loaded, such as: model = "/path/to/glm-model.RData"
  2. File path to an .R file which will be evaluated into an environment and loaded, such as: model = "/path/to/glm-model.R"
  3. An object, such as: model = am.glm

The base path for files is set to your working directory.

  • To specify a different base path for code and model arguments, use:

    opts <- serviceOption()
    opts$set("data-dir", "/base/path/to/some-other/location"))
    
  • To clear the path and specify full paths, use:

    opts <- serviceOption()
    opts$set("data-dir", NULL))
    

Using local objects for code and model

In this example, the code comes from an object (code = manualTransmission) and the model comes from a model object (model = carsModel).

##########################################################
#       Create & Test a Logistic Regression Model        #
##########################################################

# Load mrsdeploy package on R Server     
library(mrsdeploy)

# Use logistic regression equation of vehicle transmission 
# in the data set mtcars to estimate the probability of 
# a vehicle being fitted with a manual transmission 
# based on horsepower (hp) and weight (wt)


# Create glm model with `mtcars` dataset
carsModel <- glm(formula = am ~ hp + wt, data = mtcars, family = binomial)

# Produce a prediction function that can use the model
manualTransmission <- function(hp, wt) {
     newdata <- data.frame(hp = hp, wt = wt)
     predict(carsModel, newdata, type = "response")
}

# test function locally by printing results
print(manualTransmission(120, 2.8)) # 0.6418125

##########################################################
#            Log into Microsoft R Server                 #
##########################################################

# Use `remoteLogin` to authenticate with R Server using 
# the local admin account. Use session = false so no 
# remote R session started
remoteLogin("http://localhost:12800", 
            username = “admin”, 
            password = “{{YOUR_PASSWORD}}”,
            session = FALSE)

##########################################################
#             Publish Model as a Service                 #
##########################################################

# Publish as service using `publishService()` function from 
# `mrsdeploy` package. Name service "mtService" and provide
# unique version number. Assign service to the variable `api`
api <- publishService(
     "mtService",
     code = manualTransmission,
     model = carsModel,
     inputs = list(hp = "numeric", wt = "numeric"),
     outputs = list(answer = "numeric"),
     v = "v1.0.0"
)

##########################################################
#                 Consume Service in R                   #
##########################################################

# Print capabilities that define the service holdings: service 
# name, version, descriptions, inputs, outputs, and the 
# name of the function to be consumed
print(api$capabilities())

# Consume service by calling function, `manualTransmission`
# contained in this service
result <- api$manualTransmission(120, 2.8)

# Print response output named `answer`
print(result$output("answer")) # 0.6418125   

##########################################################
#       Get Swagger File for this Service in R Now       #
##########################################################

# During this authenticated session, download the  
# Swagger-based JSON file that defines this service
swagger <- api$swagger()
cat(swagger, file = "swagger.json", append = FALSE)

# Now you can share Swagger-based JSON so others can consume it

##########################################################
#          Delete service version when finished          #
##########################################################

# User who published service or user with owner role can
# remove the service when it is no longer needed
status <- deleteService("mtService", "v1.0.0")
status

##########################################################
#                   Log off of R Server                  #
##########################################################

# Log off of R Server
remoteLogout()

Using local .RData file

In this example, the code is still an object (code = manualTransmission), but the model now comes from an .Rdata file (model = "transmission.RData"). The result is still the same as in the first example.

library(mrsdeploy)

# --- AAD login ----------------------------------------------------------------

# Use `remoteLogin` to authenticate with R Server using 
# the local admin account. Use session = false so no 
# remote R session started
remoteLogin("http://localhost:12800", 
            username = “admin”, 
            password = “{{YOUR_PASSWORD}}”,
            session = FALSE)

model <- glm(formula = am ~ hp + wt, data = mtcars, family = binomial)
save(model, file = "transmission.RData")

manualTransmission <- function(hp, wt) {
  newdata <- data.frame(hp = hp, wt = wt)
  predict(model, newdata, type = "response")
}

# test locally: 0.6418125
print(manualTransmission(120, 2.8))

api <- publishService(
   "mtService",
   code = manualTransmission,
   model = "transmission.RData",
   inputs = list(hp = "numeric", wt = "numeric"),
   outputs = list(answer = "numeric"),
   v = "v1.0.2"
)

api

result <- api$manualTransmission(120, 2.8)
print(result$output("answer")) # 0.6418125

swagger <- api$swagger()
cat(swagger)

swagger <- api$swagger(json = FALSE)
swagger

services <- listServices("mtService")
services

mtService <- services[[1]]
mtService

api <- getService(mtService$name, mtService$version)
api
result <- api$manualTransmission(120, 2.8)
print(result$output("answer")) # 0.6418125

cap <- api$capabilities()
cap
cap$swagger

status <- deleteService(cap$name, cap$version)
status

remoteLogout()

Using .R files

In this example, the code (code = transmission-code.R,) and the model comes from R scripts (model = "transmission.R"). The result is still the same as in the first example.

library(mrsdeploy)

# --- AAD login ----------------------------------------------------------------

# Use `remoteLogin` to authenticate with R Server using 
# the local admin account. Use session = false so no 
# remote R session started
remoteLogin("http://localhost:12800", 
            username = “admin”, 
            password = “{{YOUR_PASSWORD}}”,
            session = FALSE)

# Information can come from a file
model <- "model <- glm(formula = am ~ hp + wt, data = mtcars, family = binomial)"
code <- "newdata <- data.frame(hp = hp, wt = wt)\n
         answer <- predict(model, newdata, type = "response")"

cat(model, file = "transmission.R", append = FALSE)
cat(code, file = "transmission-code.R", append = FALSE)

api <- publishService(
   "mtService",
   code = "transmission-code.R",
   model = "transmission.R",
   inputs = list(hp = "numeric", wt = "numeric"),
   outputs = list(answer = "numeric"),
   v = "v1.0.3",
   alias = "manualTransmission"
)

api

result <- api$manualTransmission(120, 2.8)
result
print(result$output("answer")) # 0.6418125

swagger <- api$swagger()
cat(swagger)

swagger <- api$swagger(json = FALSE)
swagger

services <- listServices("mtService")
services

mtService <- services[[1]]
mtService

api <- getService(mtService$name, mtService$version)
api
result <- api$manualTransmission(120, 2.8)
print(result$output("answer")) # 0.6418125

cap <- api$capabilities()
cap
cap$swagger

status <- deleteService(cap$name, cap$version)
status

remoteLogout()

Using .RData and .R

In this example, the code (code = transmission-code.R,) comes from an R script, and the model from an .RData file (model = "transmission.RData"). The result is still the same as in the first example.

library(mrsdeploy)

# --- AAD login ----------------------------------------------------------------

# Use `remoteLogin` to authenticate with R Server using 
# the local admin account. Use session = false so no 
# remote R session started
remoteLogin("http://localhost:12800", 
            username = “admin”, 
            password = “{{YOUR_PASSWORD}}”,
            session = FALSE)

# model
model <- glm(formula = am ~ hp + wt, data = mtcars, family = binomial)
save(model, file = "transmission.RData")

# R code
code <- "newdata <- data.frame(hp = hp, wt = wt)\n
         answer <- predict(model, newdata, type = "response")"
cat(code, file = "transmission-code.R", sep="n", append = TRUE)

api <- publishService(
   "mtService",
   code = "transmission-code.R",
   model = "transmission.RData",
   inputs = list(hp = "numeric", wt = "numeric"),
   outputs = list(answer = "numeric"),
   v = "v1.0.4",
   alias = "manualTransmission"
)

api

result <- api$manualTransmission(120, 2.8)
print(result$output("answer")) # 0.6418125

swagger <- api$swagger()
cat(swagger)

swagger <- api$swagger(json = FALSE)
swagger

services <- listServices("mtService")
services

mtService <- services[[1]]
mtService

api <- getService(mtService$name, mtService$version)
api
result <- api$manualTransmission(120, 2.8)
print(result$output("answer")) # 0.6418125

cap <- api$capabilities()
cap
cap$swagger

status <- deleteService(cap$name, cap$version)
status

remoteLogout()

See also

© 2017 Microsoft