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.