Skip to content
Plaristote edited this page Jun 12, 2018 · 1 revision

XMLRPC Server

Your crails server may act as an XMLRPC server using the crails-xmlrpc module.

To install the module, run the following command on your crails project:

crails module xmlrpc install

Implementing an xmlrpc server

Your xmlrpc server will be implemented as a crails' controller. You will need to create a class that inherits from XmlRpc::Controller:

#ifndef  MY_XMLRPC_CONTROLLER_HPP
# define MY_XMLRPC_CONTROLLER_HPP
# include <crails/xmlrpc/controller.hpp>

class MyXmlrpcController : public XmlRpc::Controller
{
public:
  MyXmlrpcController(Crails::Params& params) : XmlRpc::Controller(params)
  {
  }
};

#endif

Everything is ready for you to implement your XMLRPC-based API. Firstly, you may declare your methods within the MyXmlrpcController class. Then, you will register those methods in the class' constructor.

class MyXmlrpcController : public XmlRpc::Controller
{
public:
  MyXmlrpcController(Crails::Params& params) : XmlRpc::Controller(params)
  {
    register_method("make_addition", &MyXmlrpcController::make_addition);
  }

  void make_addition(int p1, int p2)
  {
    respond_with(p1 + p2); // sets the xmlrpc return value
  }
};

Your function parameters will be automatically filled with those provided in the XMLRPC request. Complex types such as struct and array are also supported, see the XMLRPC Types section for more details.

Registering the xmlrpc endpoint

Lastly, you will have to connect the crails router to your XMLRPC controller. To do that, you need to create a route that redirects to the endpoint method of your controller.

void Router::initialize()
{
  SetRoute("POST", "/my_xmlrpc_endpoint", MyXmlrpcController, endpoint);
}

The endpoint method is implemented in the XmlRpc::Controller, and will dispatch the request to a matching registered method (or respond with a fault response if no matching method has been found).

XMLRPC Client

You may also implement an xmlrpc client, using XmlRpc::Client.

#include <crails/xmlrpc/client.hpp>
#include <crails/xmlrpc/fault.hpp>

try
{
  XmlRpc::Client client("http://localhost:3000/xmlrpc_endpoint");
  int result = client.call("make_addition", 12, 42);

  std::cout << "call result: " << result << std::endl;
}
catch (const XmlRpc::Fault& fault)
{
  std::cout << "XmlRpc::Fault: (" << fault.fault_code() << ") " << fault.what() << std::endl;
}

Note that XmlRpc::Client::call returns an object of type XmlRpc::Variable, which can cast to any xmlrpc supported type.

XMLRPC Types

Variable

The XmlRpc::Variable type is a container that can cast to any type supported by the xmlrpc protocol.

Struct

You may implement struct objects by inheriting from the XmlRpc::Struct class.

#include <crails/xmlrpc/struct.hpp>

struct MyStruct : public XmlRpc::Struct
{
  // You must provide a constructor taking `XmlRpc::Variable` as parameter
  MyStruct(const XmlRpc::Variable& data) : Struct(data) {}
  // You must also provide a constructor that takes no parameters
  MyStruct() {}

  // The following macros allow you to declare your struct's properties
  XmlRpc_int_property(id)
  XmlRpc_string_property(name)
  XmlRpc_double_property(ratio)
  XmlRpc_bool_property(deleted)
  XmlRpc_date_property(created_at)
  XmlRpc_date_property(updated_at)

  XmlRpc_string_array_property(surnames) // append array to the type to create a property based
};

The XmlRpc_[type]_property macros will generate getter and setters for the given properties. Note that the XmlRpc_[type]_array_property macro uses std::vector to implement the array property.

Nested structs

A struct can be a member within another struct. In such a case, you need to declare both struct types as inheriting XmlRpc::Struct, and initialize the nested struct in the nesting struct constructor.

// Defining the type for the struct that will be nested
struct NestedStruct : public XmlRpc::Struct
{
  NestedStruct(const XmlRpc::Variable& data) : XmlRpc::Struct(data) {}
  NestedStruct() {}

  XmlRpc_int_property(id)
  XmlRpc_string_property(name)
};

// Defining the type for the struct that will contain NestedStruct
struct MyStruct : public XmlRpc::Struct
{
  NestedStruct nested_struct;

  MyStruct(const XmlRpc::Variable& data) :
    XmlRpc::Struct(data),
    nested_struct(data["nested_struct"]) // data["nested_struct"] will return the `XmlRpc::Variable` object
  {}                                     // for the "nested_struct" member of MyStruct.

  MyStruct();

  XmlRpc_int_property(id)
};

Array

TODO: Array support in crails-xmlrpc is still partial.

Arrays are implemented through the std::vector container. Vectors can be passed and used as parameters transparently, as long as the contained type is supported (any of the native type, or a type inheriting from XmlRpc::Struct).

Dates

Dates are implemented using the std::time_t type.