Skip to content

A full RAPP Platform service creation example advanced

Athanassios Kintsakis edited this page May 26, 2016 · 21 revisions

In this example, a basic guide will be presented that will cover the basics of creating an example RAPP Platform service. We assume that you have successfully installed the RAPP Platform and run the tests, if not please see our installation guide located at

https://github.com/rapp-project/rapp-platform/wiki/How-can-I-set-up-the-RAPP-Platform-in-my-PC%3F

It is addressed to the novice user and as such, experienced users may find it too detailed or need to skip over some sections. This tutorial assumes some basic ROS knowledge. Users not familiar with ROS are advised to first complete relevant ROS tutorials that can be found at

http://wiki.ros.org/ROS/Tutorials

By the end of the tutorial you should be able to call the service itself and obtain meaningful results. What you will learn:

  • How to create a ROS service in the RAPP Platform and how to incorporate its launcher in the RAPP Platform launchers in order for the service to start along with the other services of the RAPP Platform
  • How to call another ROS service within your service
  • How to create a ROS test for your service
  • How to create a HOP service for the ROS service that you created. The HOP service will be exposed on the network and will allow you to call the service over an http web request.

Section 1: Creating a ROS RAPP Platform example service

In this section we will cover how to create a basic ROS RAPP Platform service. Let us assume that the service we should to create takes as input two integer number, adds them together and returns the result. It also takes as input a string containing the username of a user and it returns a string containing the ontology alias of the user, by making a call to the appropriate ROS RAPP Platform service.

Create a ROS Node

The first thing to do is to create a new ROS Node which will be responsible for the service we want to implement. In order to create a new ROS node, navigate within the rapp-platform directory and create a new package:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/
$ catkin_create_pkg rapp_example_service std_msgs rospy rapp_platform_ros_communications

This command creates a new package named rapp_example_service and adds the its dependencies upon the std_msgs, rospy and rapp_platform_ros_communications packages. You can now navigate within the newly created package, and create a directory named cfg:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/
$ mkdir cfg
$ cd cfg
$ touch rapp_example_service_params.yaml
$ echo 'rapp_example_service_topic: /rapp/rapp_example_service/add_two_integers' >> rapp_example_service_params.yaml

We declared was the name of the service within the .yaml file. Now we will navigate back into the rapp_example_service package and create the launch dir.

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service
$ mkdir launch
$ cd launch
$ touch rapp_example_service.launch

The content of rapp_example_service.launch follows:

<launch>
  <node name="rapp_example_service_node" pkg="rapp_example_service" type="rapp_example_service_main.py" output="screen" />
  <rosparam file="$(find rapp_example_service)/cfg/rapp_example_service_params.yaml" command="load" />
</launch>

This file declares the launcher of the service.

Now, we will create the source code files according to the coding standards of the RAPP project.

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/src
$ touch rapp_example_service_main.py

The content of rapp_example_service_main.py follows

#!/usr/bin/env python

import rospy
from rapp_example_service import ExampleService

if __name__ == "__main__":
    rospy.init_node('ExampleService')
    ExampleServicesNode = ExampleService()
    rospy.spin()

We have declared the main function of the ROS node and launched the ROS node with the rospy.spin() command. Now we will create the rapp_example_service.py below:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/src
$ touch rapp_example_service.py

The content of rapp_example_service.py follows:

#!/usr/bin/env python

import rospy

from add_two_integers import AddTwoIntegers

from rapp_platform_ros_communications.srv import (
    tutorialExampleServiceSrv,
    tutorialExampleServiceSrvRequest,
    tutorialExampleServiceSrvResponse)

class ExampleService:

    def __init__(self):
        self.serv_topic = rospy.get_param('rapp_knowrob_wrapper_create_ontology_alias')
        if(not self.serv_topic):
            rospy.logerror("rapp_knowrob_wrapper_create_ontology_alias param not found")
        rospy.wait_for_service(self.serv_topic)

        self.serv_topic = rospy.get_param("rapp_example_service_topic")
        if(not self.serv_topic):
            rospy.logerror("rapp_example_service_topic")
        self.serv=rospy.Service(self.serv_topic, tutorialExampleServiceSrv, self.tutorialExampleServiceDataHandler)

    def tutorialExampleServiceDataHandler(self,req):
        res = tutorialExampleServiceSrvResponse()
        it = AddTwoIntegers()
        res=it.addTwoIntegersFunction(req)
        return res

In this file, we initially declare python dependencies, one of them is the AddTwoIntegers class which we will define in a new file next. As you can see, we have imported an srv message files that needs to be created and declared in the rapp_platform_ros_communications package. We will cover this shortly. We also imported the name of the service from the .yaml file located in the cfg folder by the rospy.get_param() command. As our service depends on the rapp_knowrob_wrapper_create_ontology_alias we have it wait until it is available. The return message of the service is handled by the DataHandler function we created, named tutorialExampleServiceDataHandler.

The last file we need to create is the add_two_integers.py.

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/src
$ touch add_two_integers.py

The content of add_two_integers.py follows:

#!/usr/bin/env python

import rospy
from rapp_platform_ros_communications.srv import (
    tutorialExampleServiceSrv,
    tutorialExampleServiceSrvRequest,
    tutorialExampleServiceSrvResponse,
    createOntologyAliasSrv,
    createOntologyAliasSrvRequest,
    createOntologyAliasSrvResponse)

class AddTwoIntegers:

    def addTwoIntegersFunction(self,req):
        res = tutorialExampleServiceSrvResponse()
        res.additionResult=req.a+req.b
        res.userOntologyAlias=self.getUserOntologyAlias(req.username)
        return res

    def getUserOntologyAlias(self,username):
        serv_topic = rospy.get_param('rapp_knowrob_wrapper_create_ontology_alias')
        knowrob_service = rospy.ServiceProxy(serv_topic, createOntologyAliasSrv)
        createOntologyAliasReq = createOntologyAliasSrvRequest()
        createOntologyAliasReq.username=username
        createOntologyAliasResponse = knowrob_service(createOntologyAliasReq)
        return createOntologyAliasResponse.ontology_alias

In this file, initially we define the imports again and following we define the AddTwoIntegers class and within it a simple function named addTwoIntegersFunction that accepts the service requirements as input and returns the service response. We initially construct the response named res, and we assign to the addition value the addition of the parameters a and b. The function getUserOntologyAlias defined, is tasked with calling an existing RAPP Platform service, the rapp_knowrob_wrapper_create_ontology_alias. This service will create an ontology alias for a user in case it does not already exist, or simply return the existing one if it already exists. The argument to call the service is the user's username. In this way, by calling this existing RAPP Platform service, we obtain the userOntologyAlias of a user given his username, and we assign it to the appropriate service response variable.

Create the service srv file

The srv file defines what the service will accept as input and what it will return as output. These must be declared in a special file, called the service's srv file. RAPP Platform conveniently places all ROS service srv files, as well as ROS service message files in the

/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_platform_ros_communications/

package. Let us assume that the service we should to create takes as input two integer number, adds them together and returns the result. First we need to create the .srv file declaring the inputs and outputs of the service as shown:

$ cd /rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_platform_ros_communications/srv
$ mkdir ExampleServices
$ cd ExampleServices
$ touch tutorialExampleServiceSrv.srv

The content of tutorialExampleServiceSrv.srv follows:

Header header
int32 a
int32 b
string username
---
string userOntologyAlias
int32 additionResult
string error

Toe declare the .srv file in the package, open the /rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_platform_ros_communications/rapp_platform_ros_communications/CMakeLists.txt file and add the following line within the add_service_files() block,

ExampleServices/tutorialExampleServiceSrv.srv

The whole file now should look like this:

cmake_minimum_required(VERSION 2.8.3)
project(rapp_platform_ros_communications)
set(ROS_BUILD_TYPE Release)

find_package(catkin REQUIRED COMPONENTS
  message_generation
  message_runtime
  std_msgs
  geometry_msgs
  nav_msgs
  )

################################################
## Declare ROS messages, services and actions ##
################################################

## Generate messages in the 'msg' folder
add_message_files(
  FILES
  StringArrayMsg.msg
  CognitiveExercisePerformanceRecordsMsg.msg
  MailMsg.msg
  NewsStoryMsg.msg
  WeatherForecastMsg.msg
  ArrayCognitiveExercisePerformanceRecordsMsg.msg
  CognitiveExercisesMsg.msg
  )

## Generate services in the 'srv' folder
add_service_files(
  FILES

  /ExampleServices/tutorialExampleServiceSrv.srv

  /CognitiveExercise/testSelectorSrv.srv
  /CognitiveExercise/recordUserCognitiveTestPerformanceSrv.srv
  /CognitiveExercise/cognitiveTestCreatorSrv.srv
  /CognitiveExercise/userScoresForAllCategoriesSrv.srv
  /CognitiveExercise/userScoreHistoryForAllCategoriesSrv.srv
  /CognitiveExercise/returnTestsOfTypeSubtypeDifficultySrv.srv

  /HumanDetection/HumanDetectionRosSrv.srv

  /CaffeWrapper/imageClassificationSrv.srv
  /CaffeWrapper/ontologyClassBridgeSrv.srv
  /CaffeWrapper/registerImageToOntologySrv.srv

  /DbWrapper/checkIfUserExistsSrv.srv
  /DbWrapper/getUserOntologyAliasSrv.srv
  /DbWrapper/getUserLanguageSrv.srv
  /DbWrapper/registerUserOntologyAliasSrv.srv
  /DbWrapper/getUserPasswordSrv.srv
  /DbWrapper/getUsernameAssociatedWithApplicationTokenSrv.srv
  /DbWrapper/createNewPlatformUserSrv.srv
  /DbWrapper/createNewApplicationTokenSrv.srv
  /DbWrapper/checkActiveApplicationTokenSrv.srv
  /DbWrapper/checkActiveRobotSessionSrv.srv
  /DbWrapper/addStoreTokenToDeviceSrv.srv
  /DbWrapper/validateUserRoleSrv.srv
  /DbWrapper/validateExistingPlatformDeviceTokenSrv.srv
  /DbWrapper/removePlatformUserSrv.srv
  /DbWrapper/createNewCloudAgentServiceSrv.srv
  /DbWrapper/createNewCloudAgentSrv.srv
  /DbWrapper/getCloudAgentServiceTypeAndHostPortSrv.srv

  /OntologyWrapper/createInstanceSrv.srv
  /OntologyWrapper/ontologySubSuperClassesOfSrv.srv
  /OntologyWrapper/ontologyIsSubSuperClassOfSrv.srv
  /OntologyWrapper/ontologyLoadDumpSrv.srv
  /OntologyWrapper/ontologyInstancesOfSrv.srv
  /OntologyWrapper/assertRetractAttributeSrv.srv
  /OntologyWrapper/returnUserInstancesOfClassSrv.srv
  /OntologyWrapper/createOntologyAliasSrv.srv
  /OntologyWrapper/userPerformanceCognitveTestsSrv.srv
  /OntologyWrapper/createCognitiveExerciseTestSrv.srv
  /OntologyWrapper/cognitiveTestsOfTypeSrv.srv
  /OntologyWrapper/recordUserPerformanceCognitiveTestsSrv.srv
  /OntologyWrapper/clearUserPerformanceCognitveTestsSrv.srv
  /OntologyWrapper/registerImageObjectToOntologySrv.srv
  /OntologyWrapper/retractUserOntologyAliasSrv.srv

  /FaceDetection/FaceDetectionRosSrv.srv

  /NewsExplorer/NewsExplorerSrv.srv
  /Geolocator/GeolocatorSrv.srv

  /WeatherReporter/WeatherReporterCurrentSrv.srv
  /WeatherReporter/WeatherReporterForecastSrv.srv

  /QrDetection/QrDetectionRosSrv.srv

  /Email/SendEmailSrv.srv
  /Email/ReceiveEmailSrv.srv

  /SpeechDetectionGoogleWrapper/SpeechToTextSrv.srv

  /SpeechDetectionSphinx4Wrapper/SpeechRecognitionSphinx4Srv.srv
  /SpeechDetectionSphinx4Wrapper/SpeechRecognitionSphinx4ConfigureSrv.srv
  /SpeechDetectionSphinx4Wrapper/SpeechRecognitionSphinx4TotalSrv.srv

  /AudioProcessing/AudioProcessingDenoiseSrv.srv
  /AudioProcessing/AudioProcessingSetNoiseProfileSrv.srv
  /AudioProcessing/AudioProcessingDetectSilenceSrv.srv
  /AudioProcessing/AudioProcessingTransformAudioSrv.srv

  /TextToSpeechEspeak/TextToSpeechSrv.srv

  /HazardDetection/LightCheckRosSrv.srv
  /HazardDetection/DoorCheckRosSrv.srv

  /PathPlanning/PathPlanningRosSrv.srv
  /Costmap2d/Costmap2dRosSrv.srv
  /PathPlanning/MapServer/MapServerGetMapRosSrv.srv
  /PathPlanning/MapServer/MapServerUploadMapRosSrv.srv

  /ApplicationAuthentication/UserTokenAuthenticationSrv.srv
  /ApplicationAuthentication/UserLoginSrv.srv
  /ApplicationAuthentication/AddNewUserFromStoreSrv.srv
  /ApplicationAuthentication/AddNewUserFromPlatformSrv.srv
  )

## Generate added messages and services with any dependencies listed here
generate_messages(
  DEPENDENCIES
  std_msgs  # Or other packages containing msgs
  geometry_msgs
  nav_msgs
  )

###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES rapp_platform_ros_communications
#  CATKIN_DEPENDS other_catkin_pkg
  CATKIN_DEPENDS
    message_generation
    message_runtime
    std_msgs
    geometry_msgs
  )

This line will declare the srv file we created and stage it to be compiled.

Now we need to recompile the package. We will navigate to the root RAPP Platform catkin workspace directory and compile the code as shown below:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/
$ catkin_make --pkg rapp_platform_ros_communications

this will recompile only the specific package. Sometimes it is preferable to recompile the whole project, in that case please delete the folders build and devel and compile the whole project, as shown below:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/
$ rm -rf ./build ./devel
$ catkin_make

Launch and manually test the service

In order to test that our ROS service works:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/
$ roslaunch rapp_example_service rapp_example_service.launch

With our service launched, use a different terminal and type:

$ rosservice call /rapp/rapp_example_service/add_two_integers

and immediately press tab twice in order to auto complete the service requirements. Please assign values on the parameters a and b and in the username put 'rapp' and hit enter. Voila! You can see the result in the additionResult parameter and you can see the username of the user rapp in the userOntologyAlias parameter. In case you use a different username which does not exist, the field will return blank, ''.

Create a ROS test for the service

Now we will create a ROS test that will perform a test to ensure our service is working correctly. The first thing to do is edit the CMakeLists.txt of the rapp_example_service package, to incorporate the testing dependencies. The file located at

~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/CMakeLists.txt

must now contain the following content:

cmake_minimum_required(VERSION 2.8.3)
project(rapp_example_service)

## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
  rapp_platform_ros_communications
  rospy
  std_msgs
  rostest
  )

###################################
## catkin specific configuration ##
###################################
catkin_package(
  CATKIN_DEPENDS
    rospy
    std_msgs
    rostest
    rapp_platform_ros_communications
  INCLUDE_DIRS
  )

###########
## Build ##
###########
include_directories(
  ${catkin_INCLUDE_DIRS}
  )

###########
## Build ##
###########
if (CATKIN_ENABLE_TESTING)
  #catkin_add_nosetests(tests/cognitive_exercise_system_services_functional_tests.py)
  add_rostest(tests/example_service_tests.launch)
endif()

As you can see we have added rostest in the dependencies and enabled testing. Similarly, the file located at

~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service/package.xml

must be updated in order to contain the following:

<?xml version="1.0"?>
<package>
  <name>rapp_example_service</name>
  <version>0.0.0</version>
  <description>The rapp_example_service package</description>

  <maintainer email="thanos@todo.todo">thanos</maintainer>

  <license>TODO</license>

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>rapp_platform_ros_communications</build_depend>
  <build_depend>rospy</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>rapp_platform_ros_communications</run_depend>
  <run_depend>rospy</run_depend>
  <run_depend>std_msgs</run_depend>
  <run_depend>rostest</run_depend>
  <build_depend>rostest</build_depend>


  <export>

  </export>
</package>

We have added the rostest run and build dependencies. Now we can proceed to creating the test source files. Navigate into the package folder and create the necessary files:

cd /rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_example_service
mkdir tests
touch example_service_tests.launch
touch example_service_tests.py

The content of the example_service_tests.launch file is:

<launch>
  <include file="$(find rapp_mysql_wrapper)/launch/mysql_wrapper.launch" />
  <include file="$(find rapp_knowrob_wrapper)/launch/knowrob_wrapper.launch" />
  <include file="$(find rapp_example_service)/launch/rapp_example_service.launch" />
  <test time-limit="100" test-name="rapp_example_service_tests" pkg="rapp_example_service" type="example_service_tests.py"/> 
 </launch>

The launch file declares the other ROS node dependencies and the source file of tests to run. The content of the example_service_tests.py file is:

#!/usr/bin/env python

#Copyright 2015 RAPP

PKG='rapp_example_service'

import sys
import unittest
import rospy
import roslib

from rapp_platform_ros_communications.srv import (
    tutorialExampleServiceSrv,
    tutorialExampleServiceSrvRequest,
    tutorialExampleServiceSrvResponse)


class ExampleServiceTests(unittest.TestCase):

    def test_example_service_basic(self):
        ros_service = rospy.get_param("rapp_example_service_topic")
        rospy.wait_for_service(ros_service)

        test_service = rospy.ServiceProxy(ros_service, tutorialExampleServiceSrv)

        req = tutorialExampleServiceSrvRequest()
        req.a=10
        req.b=25
        req.username="rapp"
        response = test_service(req)
        self.assertEqual(response.userOntologyAlias, "Person_DpphmPqg")
        self.assertEqual(response.additionResult, 35)


## The main function. Initializes the Cognitive Exercise System functional tests
if __name__ == '__main__':
    import rosunit
    rosunit.unitrun(PKG, 'ExampleServiceTests', ExampleServiceTests)

We have created a python unit test, where the input is checked against the expected output in order to validate the results and consequently that the service is working correctly. The last thing to do now is to perform the test. Please first recompile the project:

$ cd /rapp_platform/rapp-platform-catkin-ws/
$ rm -rf ./build ./devel
$ catkin_make

And now, in order to launch the test run the command:

$ cd /rapp_platform/rapp-platform-catkin-ws/
$ catkin_make run_tests_rapp_example_service

The result should be that 1 test executed successfully.

Section 2: Create the HOP web service

Read on How-to-create-a-HOP-service-for-a-ROS-service, if you have not done so already.

Also, this web service implementation requires to have previously read on the simple-example. The steps are the same, with a difference in the Web Service onrequest callback implementation.

Follow the steps described here to create the respective directories and source files.

The Web-Service response message includes the sum_result and error properties. The ROS Service request message has two integer properties, a and b and the username value.

var clientRes = function(sum_result, user_ontology_alias, error) {
  sum_result = sum_result || 0;
  error = error || '';
  user_ontology_alias = user_ontology_alias || ''
  return { sum_result: sum_result, user_ontology_alias: user_ontology_alias, error: error }
}

var rosReqMsg = function(a, b, username) {
  a = a || 0;
  b = b || 0;
  username = username || '';
  return { a: a, b: b, username: username }
}

The rapp_example_service ROS Service url path is /rapp/rapp_example_service/add_two_integers

var rosSrvUrlPath = "/rapp/rapp_example_service/add_two_integers"

Next you need to implement the WebService onrequest callback function. This is the function that will be called as long as a request for the rapp_example_web_service arrives.

A question comes. How will we obtain the username value to be passed to the ROS Service? The easy way is for the clients to pass the username value on the request body, but this means that the RAPP Application Authentication mechanisms break. As explained here and here, the username of the client can be found in username property of the req object, req.username, after authentication of the incoming client request.

Below is the implementation of the respective Web Service onrequest callback.

function svcImpl(req, resp, ros) {
  // Get values of 'a' and 'b' from request body.
  var numA = req.body.a;
  var numB = req.body.b;
  var username = req.username;

  // Create the rosMsg
  var rosMsg = new rosReqMsg(numA, numB, username);

  /***
   * ROS-Service response callback.
   */
  function callback(rosResponse){
    // Get the sum result value from ROS Service response message.
    var response = clientRes( rosResponse.additionResult, rosResponse.userOntologyAlias );
    // Return the sum result, of numbers 'a' and 'b', and the `user_ontology_alias` to the client.
    resp.sendJson(response);
  }

  /***
   * ROS-Service onerror callback.
   */
  function onerror(e){
    // Respond a "Server Error". HTTP Error 501 - Internal Server Error
    resp.sendServerError();
  }

  /***
   * Call ROS-Service.
   */
  ros.callService(rosSrvUrlPath, rosMsg,
    {success: callback, fail: onerror});
}

Export the service onrequest callback function (svcImpl):

module.exports = svcImpl;

Add the rapp_example_web_service entry in services.json file:

"rapp_example_web_service": {
  "launch": true,
  "anonymous": false,
  "name": "rapp_example_web_service",
  "url_name": "add_two_ints",
  "namespace": "",
  "ros_connection": true,
  "timeout": 45000
}

The Web Service will listen at http://localhost:9001/hop/add_two_ints as defined by the url_name value.

You can set the url path for the Web Service to be rapp_example_web_service/add_two_ints by setting the url_name and namespace respectively:

"rapp_example_web_service": {
  "launch": true,
  "anonymous": false,
  "name": "rapp_example_web_service",
  "url_name": "add_two_ints",
  "namespace": "rapp_example_web_service",
  "ros_connection": true,
  "timeout": 45000
}

We have also set this Web Service to timeout after 45 seconds (timeout). This is critical when WebService-to-ROS communcation bridge breaks!

For simplicity, we will configure this WebService to be launched under an already existed Web Worker thread (main-1).

The workers.json file contains Web Workers entries. Add the rapp_example_web_service service under the main-1 worker:

"main-1": {
  "launch": true,
  "path": "workers/main1.js",
  "services": [
    ...
    "rapp_example_web_service"
  ]
}

The newly implemented rapp_example_web_service Web Service is ready to be launched. Launch the RAPP Platform Web Server:

$ cd ~/rapp_platform/rapp-platform-catkin-ws/src/rapp-platform/rapp_web_services
$ pm2 start server.yaml

If you dont want to launch the Web Server using pm2 process manager, just execute the run.sh script in the same directory:

$ ./run.sh

You will notice the following output from the logs:

info: []  Registered worker service {http://localhost:9001/hop/add_two_ints} under worker thread {main-1}
info: []  
{ worker: 'main-1',
  path: '/hop/add_two_ints',
  url: 'http://localhost:9001/hop/add_two_ints',
  frame: [Function] }

All set! The RAPP Platform accepts requests for the rapp_example_web_service at http://rapp-platform-local:9001/hop/add_two_ints

You can test it using curl from commandline:

$ curl --data "a=100&b=20" http://localhost:9001/hop/add_two_ints

Notice that the RAPP Platform will return Authentication Failure (HTTP 401 Unauthorized Error). This is because the RAPP Platform uses token-based application authentication mechanisms to authenticate incoming client requests. You will have to pass a valid token to the request headers. By default, the RAPP Platform database includes a user rapp and the token is rapp_token. Pass that token value to the Accept-Token field of the request header:

$ curl -H "Accept-Token: rapp_token" --data "a=100&b=20" http://localhost:9001/hop/add_two_ints

The output should now be similar to:

{sum_result: 120, user_ontology_alias: "THE_USER_ONTOLOGY_ALIAS", error: ""}

Section 3: Update the RAPP Platform API

First, read on How to write the API for a HOP service, if you have not done so already.

The AddTwoInts Cloud Message class is identical to the simple-example presented here, with the addition of user_ontology_alias property to the AddTwoInts.Response class:

from RappCloud.Objects import (
    File,
    Payload)

from Cloud import (
    CloudMsg,
    CloudRequest,
    CloudResponse)


  class AddTwoInts(CloudMsg):
      """ Add Two Integers Exqample CloudMsg object"""

      class Request(CloudRequest):
          """ Add Two Integers Cloud Request object. AddTwoInts.Request """
          def __init__(self, **kwargs):
              """!
              Constructor
              @param **kwargs - Keyword arguments. Apply values to the request attributes.
                - @ref a
                - @ref b
              """

              ## Number #1
              self.a = 0
              ## Number #2
              self.b = 0
              # Apply passed keyword arguments to the Request object.
              super(AddTwoInts.Request, self).__init__(**kwargs)


        def make_payload(self):
            """ Create and return the Payload of the Request. """
            return Payload(a=self.a, b=self.b)

        def make_files(self):
            """ Create and return Array of File objects of the Request. """
            return []

        class Response(CloudResponse):
            """ Add Two Integers Cloud Response object. AddTwoInts.Response """
            def __init__(self, **kwargs):
                """!
                Constructor

                @param **kwargs - Keyword arguments. Apply values to the request attributes.
                - @ref error
                - @ref sum_result
                """
                ## Error message
                self.error = ''
                ## The sum result of numbers a and b
                self.sum_result = 0
                ## User's ontology alias
                self.user_ontology_alias
                ## Apply passed keyword arguments to the Request object.
                super(AddTwoInts.Response, self).__init__(**kwargs)


        def __init__(self, **kwargs):
            """!
            Constructor

            @param **kwargs - Keyword arguments. Apply values to the request attributes.
                - @ref Request.a
                - @ref Request.b
            """

            # Create and hold the Request object for this CloudMsg
            self.req = AddTwoInts.Request()
            # Create and hold the Response object for this CloudMsg
            self.resp = AddTwoInts.Response()
            super(AddTwoInts, self).__init__(svcname='add_two_ints', **kwargs)

Similar to the simple-example, append the following line of code in the RappCloud/CloudMsgs/__init__.py file:

from AddTwoInts import AddTwoInts

Now everything is in place to call the newly created RAPP Platform Service, using the python implementation of the rapp-platform-api. An example is presented below:

from RappCloud.CloudMsgs import AddTwoInts
from RappCloud import RappPlatformService

svcClient = RappPlatformService(persistent=True, timeout=1000)
msg = AddTwoInts(a=5, b=4)

response svcClient.call(msg)

print response.sum_result
>> 9
print response.user_ontology_alias
>> "THE_USER_ONTOLOGY_ALIAS"
Clone this wiki locally