RAPP Platform Wiki  v0.6.0
RAPP Platform is a collection of ROS nodes and back-end processes that aim to deliver ready-to-use generic services to robots
 All Files Pages
? How-to-write-the-API-for-a-HOP-service?

Currently, we support and maintain RAPP-API(s) for the following programming languages:

  • Python
  • JavaScript
  • C++

Under the rapp-api repository you can find more information regarding implemented and tested Rapp-Platform API calls.

As the integration tests are written in Python and uses the Python-Rapp-APi it is a good practice to start on the python-rapp-api.


Python RAPP-Platform-API Overview - Usage

API users are able to select from 2 API implementations:

  • High level API
  • Advanced API

The first one allow API users to easily call RAPP PLatform Services through simple function calls. The second one is for advanced usage, delivered for expert developers. This is an object-oriented implementation. As we will later describe, the advanced API usage allow creation of Cloud Messages. Both Platform requests and responses are described by static objects.

Note: The High Level API actually wraps the Advanced API.

Advanced API usage

RappPlatformService is the RAPP term for an established connection to the RAPP-Platform Services, over the www (World-Wide-Web). Each Platform Service has it's own unique Response and Request message.

The RappPlatformService class is used to establish connections to the RAPP-Platform Web-Services, while CloudMsg objects include:

  • Request object. RAPP-Platform Service specific Request message
  • Response object. RAPP-Platform Service specific Response message

```python from RappCloud import RappPlatformService

svcClient = RappPlatformService(persistent=True, timeout=30000) ```

By Default it connects to the localhost, assuming that the RAPP Platform has been setup on the local machine. The constructor of the RappPlatformService class allow to specify the RAPP Platform parameters to connect to.

```python from RappCloud import RappPlatformService

svcClient = RappPlatformService(address='RAPP_PLATFORM_IPv4_ADDRESS', port='RAPP_PLATFORM_PORT_NUMBER', protocol='http') ```

RappPlatformService object constructor allow to set:

  • persistent (Boolean): Force peristent connections. Defaults to True
  • timeout (Integer): Client timeout value. This is the timeout value waiting for a response from the RAPP Platform. Defaults to infinity
  • address (String): The RAPP Platform IPv4 address to connect to. Defaults to 'localhost'
  • port (String): The RAPP Platform listening port. Defaults to "9001"
  • protocol (String): The configured application protocol for the RAPP Platform. Valid values are "**https**" and "**http**". Defaults to "http"

The persistent and timeout properties of a RappPlatformService object are public members and can be set using the dot (.) notation:

```py svcClient = RappPlatformService() svcClient.persistent = True svcClient.timeout = 30000 ```

CloudMsg objects are feed to the RappPlatformService object to specific RAPP-Platform Services. CloudMsg classes can be imported from the CloudMsgs submodule of the RappCloud module:

```py from RappCloud.CloudMsgs import FaceDetection ```

The above line of code is used as an example of importing the FaceDetection CloudMsg class.

A complete description on available CloudMsg classes as long as their Request and Response message classes is available here

CloudMsg objects hold a Request and a Response object:

```py from RappCloud.CloudMsgs import FaceDetection faceDetectMsg = FaceDetection()

reqObj = faceDetectMsg.req respObj = faceDetectMsg.resp ```

Request and Response objects of a CloudMsg can be serialized to a dictionary:

```py reqDict = faceDetectMsg.req.serialize() print reqDict

{fast: False, imageFilePath: ''}

respDict = faceDetectMsg.resp.serialize() print respDict

{faces: [], error: ''}

```

CloudMsg Request property values can be set through the req property of the CloudMsg object. or as keyword arguments to the constructor of a CloudMsg:

```py from RappCloud.CloudMsgs import FaceDetection

msg = FaceDetection(imageFilepath='/tmp/face-sample.png') print msg.req.serialize()

{fast: False, imageFilepath: '/tmp/face-sample.png'}

msg.req.fast = True print msg.req.serialize()

{fast: True, imageFilepath: '/tmp/face-sample.png'}

```

RappPlatfomrService objects have a .call() method for calling RAPP-Platform Services:

```py class RappPlatformService: ...

def call(self, msg=None): ... return self.resp

... ```

The .call() method returns the Response object.

```py svcClient= RappPlatformService() msg = FaceDetection() msg.req.fast = True msg.req.imageFilepath = '/tmp/face-sample.png'

response = svcClient.call(msg) print response.faces print response.error

```

CloudMsg objects are passed as argument to the .call() method of the RappPlatformService object:

```py svcClient= RappPlatformService() msg = FaceDetection(imageFilepath='/tmp/face-sample.png') response = svcClient.call(msg) ```

CloudMsg objects can also be passed to the constructor of the RappPlatformService class:

```py faceMsg = FaceDetection(imageFilepath='/tmp/face-sample.png') svcClient= RappPlatformService(msg=faceMsg, timeout=15000) response = svcClient.call() ```

Note: Calling several different RAPP-Platform Services is done by passing the service specific Cloud Message objects to the .call() of the RappPlatformService object.

The following example creates a FaceDetection and a QrDetection CloudMsg to call both the Face-Detection and Qr-Detection RAPP-Platform Services.

```py from RappCloud import RappPlatformService from RappCloud.CloudMsgs import ( FaceDetection, QrDetection)

svcClient = RappPlatformService(timeout=1000) faceMsg = FaceDetection(fast=True, imageFilepath='/tmp/face-sample.png') qrMsg = QrDetection() qrMsg.req.imageFilepath = '/tmp/qr-sample.png'

fdResp = svcClient.call(faceMsg) print "Found %s Faces" len(fdResp.faces)

qrResp = svcClient.call(qrMsg) print "Found %s QRs: %s" %(len(qrResp.qr_centers), qrResp.qr_messages)

```

High Level API usage

Like previously mentioned, API users can also use the High Level implementation of the RAPP Platform API. Benefits from using this implementation is lack of knowledge of how Cloud Messages and RappPlatformService are used. Calls to the RAPP Platform are done through simple function calls, under the RappPlatformAPI module.

Below is an example of performing a query to the ontologyi, hosted on the RAPP Platform, using the High Level API implementation:

```python from RappCloud import RappPlatformAPI ch = RappPlatformAPI()

response = ch.ontologySubclasses("Oven")

print response

{'results': [u'http://knowrob.org/kb/knowrob.owl#MicrowaveOven', u'http://knowrob.org/kb/knowrob.owl#RegularOven', u'http://knowrob.org/kb/knowrob.owl#ToasterOven'], 'error': u''}

```

The RappPlatformAPI usage and calls are fully documented here, also with examples of usage.


Example - Implementing the FaceDetection API call.

Lets say we want to implement the FaceDetection Cloud Message.

The face detection RAPP Platform Web Service has a Request and Response object

Web-Service Request

  • fast (Boolean): If true, detection will take less time but it will be less accurate
  • file (File): Image file.

Web-Service Response

  • faces (Array): An array of the detected faces coordinates (point2D), on the image frame.
  • error (String): Error message.

Start by creating the python source file for the FaceDeteciton Cloud Message implementation. Head to the RappCloud/CloudMsgs directory of the RappCloud module and create a file named FaceDetection.py

Cloud Messages classes inherit from the CloudMsg class and Request and Response classes inherit from CloudRequest and CloudResponse classes respectively. So first import those classes and write the structure of the FaceDetection Cloud Message:

```python from Cloud import ( CloudMsg, CloudRequest, CloudResponse)

class FaceDetection(CloudMsg):

class Request(CloudRequest):
    def __init__(self, **kwargs):
        pass


class Response(CloudResponse):
    def __init__(self, **kwargs):
        pass


def __init__(self, **kwargs):
    pass

```

Add the appropriate properties to the Request and Response classes. Property names can differ from the Web-Service request and response property names. Mapping from implemented property names to actual request payload will be studied later on:

```python class Request(CloudRequest):

def __init__(self, **kwargs):
    ## File path to the image file
    self.imageFilepath = ''
    ## If true, detection will take less time but it will be less accurate
    self.fast = False
    ## Apply keyword arguments to the Request object.
    super(FaceDetection.Request, self).__init__(**kwargs)

class Response(CloudResponse):

def __init__(self, **kwargs):
    ## Error message
    self.error = ''
    ## Detected faces. Array of face objects.
    self.faces = []
    ## Apply keyword arguments to the Request object.
    super(FaceDetection.Response, self).__init__(**kwargs)

```

Notice calling CloudResponse and CloudRequest construcors.

Remember that a Request class must implement two member methods, make_payload() and make_files. For the payload it's the fast property and imageFilepath is a file.

```python from RappCloud.Objects import ( Payload, File)

class Request(CloudRequest):

def __init__(self, **kwargs):
    ## File path to the image file
    self.imageFilepath = ''
    ## If true, detection will take less time but it will be less accurate
    self.fast = False
    ## Apply keyword arguments to the Request object.
    super(FaceDetection.Request, self).__init__(**kwargs)

def make_payload(self):
    return Payload(fast=self.fast)

def make_files(self):
    return [File(filepath=self.path, postfield="file")]

```

Next, you have to instantiate a Request and Response objects for the FaceDetection class to hold:

```python class FaceDetection(CloudMsg): ...

def init(self, **kwargs):

Create and hold the Request object for this CloudMsg

self.req = FaceDetection.Request()

Create and hold the Response object for this CloudMsg

self.resp = FaceDetection.Response() ```

Each RAPP Platform Web Service has a unique service name resolving to a url name/path. The service name for the Face Detection RAPP Platform Web Service is:

```shell face_detection ```

CloudMsg constructor takes as input the service name:

```python class FaceDetection(CloudMsg): ...

def init(self, **kwargs):

Create and hold the Request object for this CloudMsg

self.req = FaceDetection.Request()

Create and hold the Response object for this CloudMsg

self.resp = FaceDetection.Response() super(FaceDetection, self).__init__(svcname='face_detection', **kwargs) ```

Note: Dont forget to document the code using doxygen

Below is the complete FaceDetection.py file

```python from RappCloud.Objects import ( File, Payload)

from Cloud import ( CloudMsg, CloudRequest, CloudResponse)

class FaceDetection(CloudMsg): """ Face Detection CloudMsg object"""

class Request(CloudRequest): """ Face Detection Cloud Request object. FaceDetection.Request """ def init(self, **kwargs): """! Constructor

Parameters
**kwargs- Keyword arguments. Apply values to the request attributes.
  • imageFilepath
  • fast"

File path to the image to load. This is the image to perform

face-detection on.

self.imageFilepath = ''

If true, detection will take less time but it will be less

accurate

self.fast = False

Apply passed keyword arguments to the Request object.

super(FaceDetection.Request, self).__init__(**kwargs)

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

    def make_files(self):
        """ Create and return Array of File objects of the Request. """
        return [File(self.imageFilepath, postfield='file')]

    class Response(CloudResponse):
        """ Face Detection Cloud Response object. FaceDetection.Response """
        def __init__(self, **kwargs):
            """!
            Constructor

            @param **kwargs - Keyword arguments. Apply values to the request attributes.
            - @ref error
            - @ref faces
            """
            ## Error message
            self.error = ''
            ## Detected faces. Array of face objects. TODO create face object.
            self.faces = []
            ## Apply passed keyword arguments to the Request object.
            super(FaceDetection.Response, self).__init__(**kwargs)


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

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

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

```

Finally append the following line of code in the RappCloud/CloudMsgs/__init__.py file:

```python from FaceDetection import FaceDetection ```

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

```python from RappCloud.CloudMsgs import FaceDetection from RappCloud import RappPlatformService

svcClient = RappPlatformService(persistent=True, timeout=30000) msg = FaceDetection(imageFilepath="PATH", fast=True)

response svcClient.call(msg)

if response.error: print "An error has occured: %s" response.error else: print response.faces ```

If you want to also include it in the High Level API implementation, you will have to modify the RappPlatformApi.py file.

First import the FaceDetection Cloud Message, that was previously implemented:

```py ...

from CloudMsgs import FaceDetection ```

Next, we must implemend the faceDetection method for the RappPlatformAPI class. Input arguments to the method are:

  • imageFilepath: Path to the image file to perform face detection on.
  • fast: Force fast detection. If true, detection takes less time but it will be less accurate

The output is a python dict of the response fields:

  • faces: Detected faces
  • error: Error message, if one occures.

The faceDetection method implementation must be as presented below

```py ...

class RappPlatformAPI(): """ RAPP Platform simple API implementation """ def init(self): self.svc_caller = RappPlatformService()

...

def faceDetection(self, imageFilepath, fast = False): """! Face detection API service call. imageFilepath: string

Parameters
imageFilepathPath to the image file. fast: bool
fastPerform fast detection. If true, detection will take less time but it will be less accurate. : dict
Returns
: Returns a dictionary of the service call response. {'faces': [], 'error': ''} """ msg = FaceDetection() try: msg.req.imageFilepath = imageFilepath response = self.svc_caller.call(msg) except Exception as e: response = FaceDetection.Response(error=str(e)) return { 'faces': response.faces, 'error': response.error } ```

Note: Make sure to launch both the back-end and the, listening for requests, HOP Web Server, of the RAPP Platform, before executing the above example. Here you can find instructions on how to launch the RAPP Platform.