diff --git a/doc/SoapServerTutorial.md b/doc/SoapServerTutorial.md index 927e4c5..bcf44e0 100644 --- a/doc/SoapServerTutorial.md +++ b/doc/SoapServerTutorial.md @@ -4,25 +4,28 @@ Suppose you want to provide a calculator web service just like the one from [Par Firstly, create a class `CalcService` which is derived from `webcc::SoapService`, override the `Handle` method: ```cpp +// calc_service.h + #include "webcc/soap_service.h" class CalcService : public webcc::SoapService { public: - CalcService() = default; - 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 from request. -- Get parameters from request. + +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. ```cpp +// calc_service.cpp + #include "calc_service.h" #include "boost/lexical_cast.hpp" @@ -40,36 +43,29 @@ bool CalcService::Handle(const webcc::SoapRequest& soap_request, 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_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; - - } else { - // NOT_IMPLEMENTED } + + // Other operations ... + } catch (boost::bad_lexical_cast&) { - // BAD_REQUEST + // ... } return false; } ``` -The `main` function would be: +Next step, create a `SoapServer` and register `CalcService` to it with a URL. + ```cpp int main(int argc, char* argv[]) { - if (argc != 2) { - std::cout << "Usage: " << argv[0] << " " << std::endl; - std::cout << " E.g.," << std::endl; - std::cout << " " << argv[0] << " 8080" << std::endl; - return 1; - } + // Check argc and argv ... unsigned short port = std::atoi(argv[1]); @@ -79,16 +75,61 @@ int main(int argc, char* argv[]) { try { webcc::SoapServer server(port, workers); - server.RegisterService(std::make_shared(), - "/calculator"); + server.RegisterService(std::make_shared(), "/calculator"); server.Run(); } catch (std::exception& e) { - std::cerr << "exception: " << e.what() << std::endl; + 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, the client HTTP request will be: +``` +POST /calculator HTTP/1.1 +Content-Type: text/xml; charset=utf-8 +Content-Length: 263 +Host: localhost:8080 +SOAPAction: add + + + + + + 1.000000 + 2.000000 + + + +``` + +And the HTTP response is: +``` +HTTP/1.1 200 OK +Content-Type: text/xml; charset=utf-8 +Content-Length: 262 + + + + + + 3.000000 + + + +``` + +See [example/soap_calc_server](example/soap_calc_server) for the full example.