You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
WebCC/doc/SoapServerTutorial.md

3.9 KiB

SOAP Server Tutorial

Suppose you want to provide a calculator web service just like the one from ParaSoft.

Firstly, create a class CalcService which is derived from webcc::SoapService, override the Handle method:

// calc_service.h

#include "webcc/soap_service.h"

class CalcService : public webcc::SoapService {
public:
  bool Handle(const webcc::SoapRequest& soap_request,
              webcc::SoapResponse* soap_response) override;
};

The Handle method has two parameters, one for request (input), one for response (output).

The implementation is quite straightforward:

  • Get operation (e.g., add) from request;
  • Get parameters (e.g., x and y) from request;
  • Calculate the result.
  • Set namespaces, result name and so on to response.
  • Set result to response.
// calc_service.cpp

#include "calc_service.h"

#include "boost/lexical_cast.hpp"

#include "webcc/soap_request.h"
#include "webcc/soap_response.h"

bool CalcService::Handle(const webcc::SoapRequest& soap_request,
                         webcc::SoapResponse* soap_response) {
  try {
    if (soap_request.operation() == "add") {
      double x = boost::lexical_cast<double>(soap_request.GetParameter("x"));
      double y = boost::lexical_cast<double>(soap_request.GetParameter("y"));

      double result = x + y;

      soap_response->set_soapenv_ns(webcc::kSoapEnvNamespace);
      soap_response->set_service_ns({ "cal", "http://www.example.com/calculator/" });
      soap_response->set_operation(soap_request.operation());
      soap_response->set_result_name("Result");
      soap_response->set_result(std::to_string(result));

      return true;
    }

    // Other operations ...

  } catch (boost::bad_lexical_cast&) {
    // ...
  }

  return false;
}

Next step, create a SoapServer and register CalcService to it with a URL.

int main(int argc, char* argv[]) {
  // Check argc and argv ...

  unsigned short port = std::atoi(argv[1]);

  // Number of worker threads.
  std::size_t workers = 2;

  try {
    webcc::SoapServer server(port, workers);

    server.RegisterService(std::make_shared<CalcService>(), "/calculator");

    server.Run();

  } catch (std::exception& e) {
    std::cerr << "Exception: " << e.what() << std::endl;
    return 1;
  }

  return 0;
}

The server is created with a port number which will be listened on to asynchnously accept client connections. The connections will be firstly put into a queue and then processed by the worker threads. The number of worker threads is determined by the workers parameter.

When register service, the URL is what the clients will put in the HTTP request to access your service:

POST /calculator HTTP/1.1

Registering multiple services to a server is allowed, but the URL must be unique for each service.

To invoke the add operation of the calculator service, an example of the client HTTP request would be:

POST /calculator HTTP/1.1
Content-Type: text/xml; charset=utf-8
Content-Length: 263
Host: localhost:8080
SOAPAction: add

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
                <ser:add xmlns:ser="http://www.example.com/calculator/">
                        <ser:x>1.000000</ser:x>
                        <ser:y>2.000000</ser:y>
                </ser:add>
        </soap:Body>
</soap:Envelope>

And the HTTP response is:

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 262

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
        <soap:Body>
                <cal:addResponse xmlns:cal="http://www.example.com/calculator/">
                        <cal:Result>3.000000</cal:Result>
                </cal:addResponse>
        </soap:Body>
</soap:Envelope>

See example/soap_calc_server for the full example.