-
Notifications
You must be signed in to change notification settings - Fork 20
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.
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.
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
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.
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:
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:
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:
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:
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:
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:
class RappPlatformService:
...
def call(self, msg=None):
...
return self.resp
...
The .call()
method returns the Response object.
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:
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:
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.
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)
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:
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.
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:
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:
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.
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:
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:
face_detection
CloudMsg
constructor takes as input the service name:
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
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
@param **kwargs - Keyword arguments. Apply values to the request attributes.
- @ref imageFilepath
- @ref 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:
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:
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:
...
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
...
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.
@type imageFilepath: string
@param imageFilepath: Path to the image file.
@type fast: bool
@param fast: Perform fast detection. If true, detection will take
less time but it will be less accurate.
@rtype: dict
@return: 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.
RAPP Project, http://rapp-project.eu/