Getting Started with gSOAP
For over two decades, Genivia's gSOAP software drives systems in industry, including the financial, telecom, health, automotive, defense, energy and publishing industries. Millions of products and services use gSOAP world wide, including products and services developed by top technology companies, such as Accenture, Adobe, Apple, Broadcom, Cisco, Comcast, Dell, eBay, EMC, ExxonMobile, Google, HP, IBM, Intel, Leidos, Microsoft, Motorola, NetApp, Nokia, Oracle, Samsung, Shell, SAP, Symantec, VeriSign, VMware, Wind River, and Xerox.
As developers ourselves, we fully understand the demands and challenges to implement modern Web services and REST APIs that must be fast, rock-solid robust, and secure. The gSOAP toolkit allows C/C++ developers to focus on application logic instead of infrastructure, resulting in reduced development time, fewer bugs, and faster time to market.
This introduction is offered as a starting point for developers. [Tutorials](tutorials.html) and the full [documentation](docs.html) are also available.
What gSOAP can do for you {#what}
---
- Automatically generate C and C++ source code to consume and deploy XML and JSON REST APIs and SOAP/XML Web services APIs, allowing you to focus on application logic instead of infrastructure
- Implement portable [fast and lean APIs](#performance) that handle 10K+ messages per second with just a few KB of code and data using gSOAP's fast XML stream processing model for XML parsing and validation
- [Convert WSDLs to efficient C or C++ source code](#services) to consume and deploy XML Web services
- [Convert XML schemas (XSDs) to efficient C or C++ source code](#services) to consume and deploy XML REST APIs
- Efficiently serialize and deserialize user-defined C and C++ data in XML with gSOAP's powerful [XML data bindings](#bindings), which helps you to rapidly develop type-safe APIs by static typing to avoid runtime errors
- Generate efficient C and C++ code for large and complex XML specifications defined by WSDLs and XSDs, such as for [eBay](http://developer.ebay.com/DevZone/guides/ebayfeatures/basics/SystemRequirements.html), [ONVIF](https://www.onvif.org/profiles/specifications/), [HL7](http://www.hl7.org/implement/standards/), [FHIR](https://www.hl7.org/fhir/downloads.html), [HIPAA 5010](http://store.x12.org/store/healthcare-4050-5010-tr3-schemas), [CDISC](https://www.cdisc.org/standards), [XMPP XEP](https://xmpp.org/extensions/), [TR-069](https://www.genivia.com/examples/tr069/index.html), [AWS](https://www.genivia.com/examples/aws/index.html), [EWS](https://www.genivia.com/examples/ews/index.html), [ACORD](https://www.acord.org/standards/downloads/Pages/default.aspx), [ISO 20022 and SWIFT](https://www.swift.com/standards/about-iso-20022/supporting-iso-20022), [FixML](https://www.fixtrading.org/standards/fixml/), [XBRL](https://en.wikipedia.org/wiki/XBRL), [OTA](http://opentravelmodel.net/pubs/specifications/Specifications.html), [IATA NDC](http://www.iata.org/whatwedo/airline-distribution/ndc/Pages/schema-description.aspx), [FedEx](https://www.fedex.com/us/developer/WebHelp/ws/2015/html/WebServicesHelp/WSDVG/1_WSDL_Introduction.htm) and more
- Safety comes first: gSOAP is not vulnerable to XML attacks such as [Billion Laughs](https://en.wikipedia.org/wiki/Billion_laughs_attack) and *quadratic blowup entity expansion* attacks, *external entity expansion* and *DTD retrieval* attacks, and [Zip bomb](https://en.wikipedia.org/wiki/Zip_bomb) attacks (which is not specific to XML)
- Securely consume and deploy APIs with HTTP/S, [WS-Security](doc/wsse/html/wsse.html) and [WS-Trust](doc/wst/html/index.html) with SAML tokens
- Test your SOAP/XML APIs with the [test messenger](doc/testmsgr/html/index.html) CLI, which automatically generates complete and randomized SOAP/XML messages based on WSDLs (using wsdl2h and soapcpp2 with option -g) to test your Web Services APIs and clients
- Use gSOAP's [unique and powerful schema slicing](slicing.html) methods, using wsdl2h option -O2 or -O4 to optimize your XML code base for size by automatically removing unused schema components from WSDLs and XSDs
- Consume and deploy JSON REST APIs, see for example our [GitHub JSON REST API](#git) example
- Deploy APIs anywhere as stand-alone gSOAP Web servers (see our [tutorials](tutorials.html) on how to implement and deploy gSOAP Web services) including [containerizing gSOAP services](examples/docker/index.html) with Docker containers and Kubernetes.
- Deploy APIs in an Apache Web server with the [gSOAP Apache module](doc/apache/html/index.html) and in IIS with the [gSOAP ISAPI extension](doc/isapi/html/index.html)
- Consume APIs with the [gSOAP cURL plugin](doc/curl/html/index.html) and [gSOAP WinInet plugin](doc/wininet/html/index.html)
- Meet industry standards for XML, including XML REST and SOAP, WSDL, MIME, MTOM, DIME, [WS-Trust](https://www.genivia.com/doc/wst/html/index.html), [WS-Security](https://www.genivia.com/doc/wsse/html/wsse.html) (with WS-Policy and WS-SecurityPolicy integrated), [WS-ReliableMessaging](https://www.genivia.com/doc/wsrm/html/wsrm_0.html), [WS-Discovery](https://www.genivia.com/doc/wsdd/html/wsdd_0.html), [WS-Addressing](https://www.genivia.com/doc/wsa/html/wsa_0.html) and more
- Build your projects on a mature source code base that is actively maintained since 2001
- Learn how to consume and deploy SOAP and REST APIs by example, see our [small to large examples](examples/calc/index.html) and ...
- ... check out a C example SOAP API [client](#client-c) and [server](#server-c) or a C++ example SOAP API [client](#client-cpp) and [server](#server-cpp), and ...
- ... check out the 40+ examples included in the gSOAP source code
These are some of the highlights that the gSOAP toolkit has to offer. If you are new to gSOAP then start with [hello world: getting started with SOAP APIs](#how-soap) and [hello world: getting started with REST APIs.](#how-rest) To learn more about our gSOAP tools and libraries, see our [overview](#overview) and [gSOAP tooling](#services) for details. Also check out our online [tutorials](tutorials.html) and [documentation](docs.html) with in-depth topics. The gSOAP examples, tutorials and documentation assumes that you have downloaded a copy of gSOAP. To download the gSOAP toolkit commercial edition or to download the open source GPLv2 gSOAP toolkit, please visit our [gSOAP product](products.html#gsoap) page.
For assistance with the installation of gSOAP on your system, see the [download and installation](downloads.html) instructions.
[![To top](images/go-up.png) To top](#)
Hello world: getting started with SOAP APIs {#how-soap}
---
You can easily consume and deploy SOAP/XML Web services APIs with the gSOAP auto-coding CLI tools and library.
For example, let's implement a simple SOAP `hello` API that accepts a name and returns the greeting "Hello *name*". The API uses XML, but you really do not need to work with XML at all because we use the gSOAP XML data binding for C++ which makes our code much easier to use compared to DOM or SAX. Our `hello` API is simply declared as an (XML namespace qualified with `ns__`) function in our `hello.h` header file:
// hello.h
int ns__hello(std::string name, std::string& greeting);
That's it! We simply generate the API source code form this `hello.h` service interface header file using the gSOAP soapcpp2 CLI:
[command]
soapcpp2 hello.h
This generates the source code we need for our SOAP/XML API. But we should also implement our API functionality before we can build and deploy our API. At a minimum we need to define `main()` and add a function `ns__hello()` to implement our `hello` API functionality:
// hello.cpp
#include "soapH.h" // include the generated source code headers
#include "ns.nsmap" // include XML namespaces
int main()
{
return soap_serve(soap_new());
}
int ns__hello(struct soap *soap, std::string name, std::string& greeting)
{
greeting = "Hello " + name;
return SOAP_OK;
}
We compile `hello.cpp` together with the generated `soapC.cpp` and `soapServer.cpp` code and the `libgsoap++` library for C++ (or the `libgsoap` library for C):
[command]
c++ -o hello.cgi hello.cpp soapC.cpp soapServer.cpp -lgsoap++
If the gSOAP libraries were not installed, then compile `stdsoap2.cpp` instead, assuming `stdsoap2.h` and `stdsoap2.cpp` are located in the working directory:
[command]
c++ -o hello.cgi hello.cpp soapC.cpp soapServer.cpp stdsoap2.cpp
Note that this ignores the `config.h` machine configuration produced with `./configure` (autotools are commonly used on *nix systems). To use the `config.h` configuration to compile the source code files, see [gSOAP libraries versus compiling from source.](#libraries)
Now you can immediately deploy `hello.cgi` as a (Fast)CGI application. But there are many other (and better) ways to deploy this API. See our [tutorials](tutorials.html) on how to implement and deploy gSOAP Web service APIs.
The soapcpp2 CLI also generated a WSDL `ns.wsdl` for us that we can publish and share with others to consume our API.
You can also use the gSOAP wsdl2h CLI to convert one or more WSDLs to an interface header file that has the Web service definitions in readable C/C++ syntax.
To consume our example `hello` API in your application is also very easy. You only need the source code generated by the soapcpp2 CLI and make the API call in your code as follows:
#include "soapH.h"
#include "ns.nsmap" // include XML namespaces
struct soap *soap = soap_new(); // new context
std::string greeting;
if (soap_call_ns__hello(soap, "http://yourdomain/cgi/hello.cgi", NULL, "world", greeting) == SOAP_OK)
std::cout << greeting << std::endl;
else
soap_stream_fault(soap, std::cerr);
soap_destroy(soap); // delete managed deserialized C++ instances
soap_end(soap); // delete other managed data
soap_free(soap); // free context
Compile your application, say `myapp.cpp` together with the generated `soapC.cpp` and `soapClient.cpp` code and the `stdsoap2.cpp` library:
[command]
c++ -o myapp myapp.cpp soapC.cpp soapClient.cpp stdsoap2.cpp
This was just a simple SOAP API example. For more details and examples to consume and deploy gSOAP Web services and REST APIs, see [gSOAP tooling for Web services and REST APIs.](#services) To learn more about XML data bindings that are used to create and consume XML messages, see [XML data bindings.](#bindings)
[![To top](images/go-up.png) To top](#)
Hello world: getting started with REST APIs {#how-rest}
---
You can easily consume and deploy REST APIs with the gSOAP soapcpp2 CLI for XML REST APIs.
Building on the previous hello world example, let's implement an XML REST API by simply running soapcpp with option `-0`:
[command]
soapcpp2 -0 hello.h
That's it! No changes needed to your code base. Option `-1` generates SOAP 1.1 code, option `-2` generates SOAP 1.2 code and option `-0` removes SOAP. All options generate code for HTTP POST methods to send and receive data.
Another approach to implement REST APIs with HTTP POST but also GET, PUT and DELETE is to use the powerful gSOAP [XML data bindings](#bindings) for C and C++. You can also use the gSOAP [JSON/JSONPath](doc/xml-rpc-json/html/index.html) library to consume and deploy JSON REST APIs. See also the [GitHub JSON REST API](#git) example.
For example, let's implement an XML REST API in C++ using XML data bindings to efficiently serialize a `` request in XML and serialize a `` response of our `hello` XML REST API:
// api.h
class hello // a XML message is simply a hello class with members (sub-elements)
{
public:
std::string name; // a message has a element
hello(const std::string &text); // construct a text message
};
class greeting // a XML message is simply a greeting class with members (sub-elements)
{
public:
std::string message; // a has a element
greeting(const std::string& text); // construct a text
};
Public class variables can be serialized in XML. Next, we generate the API source code from our `api.h` data binding interface header file:
[command]
soapcpp2 api.h
Note that the `api.h` header file cannot include source code for the class methods, so we should implement the constructor in `api.cpp`:
// api.cpp
hello::hello(const std::string& text)
{
name = text;
}
greeting::greeting(const std::string& text)
{
message = text;
}
To implement and deploy a REST API, our `api.cpp` code should also have a `main()` that uses the gSOAP HTTP POST plugin for REST APIs:
// api.cpp
#include "soapH.h" // include the generated source code headers
#include "soap.nsmap" // include XML namespaces
#include "plugin/httppost.h" // HTTP POST plugin for gSOAP servers
int xml_handler(struct soap*);
struct http_post_handlers handlers[] =
{
{ "text/xml", xml_handler }, // handle POST text/xml messages (you can add other MIME types and handlers here)
{ NULL }
};
int main()
{
struct soap *soap = soap_new(); // new context
soap_register_plugin_arg(soap, http_post, handlers); // register HTTP POST plugin
soap_serve(soap); // run server
soap_destroy(soap); // clean up
soap_end(soap); // clean up
soap_free(soap); // free context
}
int xml_handler(struct soap *soap) // REST API function
{
hello request;
if (soap_get_hello(soap, &request, "hello", NULL)) // try getting
return soap->error; // no (you can try to get other XML here)
greeting response("Hello " + request.name); // create Hello name
soap->http_content = "text/xml"; // HTTP content: text/xml
if (soap_response(soap, SOAP_FILE) // HTTP 200 OK
|| response.soap_put(soap, "greeting", NULL); // HTTP body with
|| soap_end_send(soap))
return soap->error;
return SOAP_OK;
}
Since we did not auto-generate the `soapServer.cpp` source code that has the `soap_serve()` function that we also need to run a server, we should use the following replacement:
soap_serve(struct soap *soap)
{
soap->keep_alive = soap->max_keep_alive + 1;
do
{
if (soap->keep_alive > 0 && soap->max_keep_alive > 0)
soap->keep_alive--;
if (soap_begin_serve(soap))
{
if (soap->error >= SOAP_STOP)
continue;
return soap->error;
}
soap_closesock(soap);
} while (soap->keep_alive);
return SOAP_OK;
}
We compile our REST API with
[command]
c++ -o api.cgi api.cpp soapC.cpp stdsoap2.cpp plugin/httppost.c
and deploy `api.cgi` as a CGI application. There are many other (and better) ways to deploy this API. See our [tutorials](tutorials.html) on how to implement and deploy gSOAP Web services.
When using MSVC++ to compile C++ applications, please rename `httppost.c` to `httppost.cpp`. Otherwise compilation and link errors may occur.
To consume an XML REST API in C++ we invoke the auto-generated `soap_POST_send_hello` and `soap_POST_receive_greeting` functions:
// myapp.cpp
#include "soapH.h" // include the generated source code headers
#include "soap.nsmap" // include XML namespaces
int main()
{
struct soap *soap = soap_new();
hello request("world");
greeting response;
if (soap_POST_send_hello(soap, "http://yourdomain/cgi/api.cgi", &request) == SOAP_OK
&& soap_POST_recv_greeting(soap, &response) == SOAP_OK)
std::cout << response.message << std::endl;
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
}
We compile our app with
[command]
c++ -o myapp myapp.cpp soapC.cpp stdsoap2.cpp
We used HTTP POST for this example. A HTTP GET API is similar. See the HTTP GET plugin include with the gSOAP software for details.
This was just a simple example. For more details and code to consume and deploy gSOAP Web services and REST APIs, see [gSOAP tooling for Web services and REST APIs.](#services) To learn more about XML data bindings that are used to create and consume XML messages, see our [XML data bindings](doc/databinding/html/index.html) documentation.
[![To top](images/go-up.png) To top](#)
Overview of gSOAP tools and libraries {#overview}
---
After [download and installation](downloads.html) of the gSOAP software, you will get several development tools and libraries:
- The **wsdl2h** tool translates WSDL and XSD files to a gSOAP header file with the **data binding interface**.
- The **soapcpp2** tool takes a header file with the data binding interface and generates the **data binding implementation** with **XML serializers** to implement Web services and XML data bindings. The generated code is platform independent and portable.
- The **runtime engine** handles HTTP and XML transport over any IO device and sockets and is responsible for memory allocation. The runtime is configured per platform and declared in `stdsoap2.h` and implemented in `stdsoap2.c` (for C) and `stdsoap2.cpp` (for C++). Also, gSOAP installs `libgsoap`, `libgsoapssl`, `libgsoap++`, and `libgsoapssl++` libraries, see further below.
- The [Apache module](doc/apache/html/index.html) and [ISAPI extension](doc/isapi/html/index.html) are bundled with gSOAP to deploy services, see our [tutorials](tutorials.html) for assistance with Web service deployments.
- The **XML DOM API** and **DOM parser** are implemented in `dom.c` (for C) and `dom.cpp` (for C++). XML DOM is used by the WS-Security plugin and to store *`xsd:anyType`* and *`xsd:any`* XML data. The gSOAP DOM API offers a hybrid **DOM + data binding approach** that allows you to embed serializable C/C++ data types in a DOM node graph. See [XML DOM API and domcpp.](doc/dom/html/index.html)
- The **domcpp** CLI generates C or C++ source code to parse, search, manipulate, and write raw XML using the DOM API and DOM parser. The tool takes an XML file or XPath query. The domcpp tool is part of the XML DOM examples in `gsoap/samples/dom` in the gSOAP source code tree. See [XML DOM API and domcpp](doc/dom/html/index.html) for more details.
- The **XML-RPC** and **JSON** libraries and examples are located in `gsoap/samples/xml-rpc-json` in the download package. See [XML-RPC/JSON and jsoncpp.](doc/xml-rpc-json/html/index.html)
- The **jsoncpp** CLI generates C or C++ source code to parse, manipulate, and write JSON data. The tool takes a JSON file or JSONPath query. See [XML-RPC/JSON and jsoncpp](doc/xml-rpc-json/html/index.html) for more details.
- The **testmsgr** CLI generates test messages to test XML APIs (client and server). See [Test Messenger](doc/testmsgr/html/index.html) for more details.
- Demonstration examples can be found [here.](examples/calc/index.html). More examples are located in the `gsoap/samples` directory in the gSOAP source code tree. See also a simple C example SOAP API [client](#client-c) and [server](#server-c) or a simple C++ example SOAP API [client](#client-cpp) and [server.](#server-cpp)
The wsdl2h CLI does exactly what the name suggests: it translates WSDL files into .h header files with data binding interface declarations of services and their C/C++ data. The wsdl2h CLI is a gSOAP application itself and uses data binding code generated for the schemas of WSDL specifications and the W3C XML schema-of-schemas.
The soapcpp2 CLI runs as a C/C++ preprocessor on a .h header file with the data binding interface to generate the source code "glue" that implements services and XML data bindings with XML serializers for your projects.
It is also possible to use soapcpp2 without wsdl2h by declaring services and XML data binding types directly in familiar C/C++ syntax. In this scenario, the soapcpp2 CLI also generates WSDL and XSD files that describe the services and data bindings.
The gSOAP runtime engine is installed as a library compiled from `stdsoap2.c` + `dom.c` and `stdsoap2.cpp` + `dom.cpp` that you can link to your project code:
- `gsoap/libgsoap.a` the C runtime engine (plain and compact, no HTTPS)
- `gsoap/libgsoapssl.a` the C runtime engine with DOM support, zlib, and SSL/TLS
- `gsoap/libgsoap++.a` the C++ runtime engine (plain and compact, no HTTPS)
- `gsoap/libgsoapssl++.a` the C++ runtime engine with DOM support, zlib, and SSL/TLS
The extended SSL/TLS versions of the library are recommended for your project, since HTTPS and HTTP compression are widely in use. If you want to use the source code of the runtime engine and DOM parser instead of the extended SSL/TLS versions of the library, then you must compile all sources with compiler flags `-DWITH_DOM`, `-DWITH_GZIP`, `-DWITH_OPENSSL`, and optionally compile with `-DWITH_IPV6` for IPv6 support. Link the OpenSSL libraries with `-lcrypto -lssl`.
Instead of [OpenSSL](http://www.openssl.org), you can use [GNUTLS](http://www.gnutls.org) or [WolfSSL](https://www.wolfssl.com) instead. See our [Tutorials](https://www.genivia.com/tutorials.html#tls) for details.
[![To top](images/go-up.png) To top](#)
gSOAP libraries versus compiling from source {#libraries}
---
You do not need to use any of the installed gSOAP libraries (see the previous section) for your project if you compile your project from source. Note that compiling from source ignores the `config.h` machine configuration produced with `./configure`. This is almost never a problem, because `stdsoap2.h` is self-configuring. However, if you run into compilation problems, then you may want to use the `config.h` configuration produced by `./configure` to compile the source code files `stdsoap2.c`, `stdsoap2.cpp`, `dom.c` and/or `dom.cpp`. To do so, specify the `HAVE_CONFIG_H` flag and place a copy of `config.h` in the working directory. For example, to compile `stdsoap2.cpp`, `dom.cpp` and other source code files:
[command]
c++ -DHAVE_CONFIG_H stdsoap2.cpp dom.cpp ...
[![To top](images/go-up.png) To top](#)
gSOAP tooling for Web services and REST APIs {#services}
---
You can implement client and server-side XML Web services in C or in C++ without much coding effort by taking advantage of the gSOAP tools to generate source code to implement the Web services API. This introduction presents the basics that you will need to know to get started quickly developing your own services and to consume services.
### Tooling overview
Use the **wsdl2h** tool to convert one or more WSDL, WADL, and/or XSD files to a gSOAP header file from the command line:
[command]
wsdl2h [options] -o file.h ... WSDL and XSD files or URLs to WSDLs and XSDs ...
When developing an application for multiple Web services, you can use wsdl2h on multiple WSDLs to generate code. The wsdl2h CLI converts WSDL and XSD files to C++ (or pure C with wsdl2h option `-c`) and saves the declarations in file.h as specified by the command line example above. This special header file contains the **data binding interface** that uses familiar C/C++ syntax extended with directives and annotations. These directives and annotations are used by the **soapcpp2** tool to generate the **data binding implementation** code and services, also from the command line:
[command]
soapcpp2 [options] file.h
The code generation steps are illustrated in more detail in the figure below (click image to enlarge). The interface file (blue box) is generated by wsdl2h from a set of WSDL and XSD files (green box). Optional parts are shown dashed. The interface file is then input to the soapcpp2 CLI together with imported protocol declarations and custom serializers. The soapcpp2 CLI generates the data binding implementation and service code (blue boxes) for the application (red box) shown at the right of the image):
Omitting the first step in this two-stage process is perfectly fine for two reasons: to develop new Web services from scratch from an existing interface header file or when upgrading gSOAP to a newer version since newer versions are backward compatible to previous interface header files. For the first case, to publish a C/C++ code base as a Web services API, simply write your own interface file to generate data binding code, services, and the WSDL and XML schema files that describe your services and your serialized XML. An interface file can be as simple as a [one liner](examples/time/index.html) Web service:
t__gmt(time_t*);
OK, this example isn't too useful, with only one Web service API function `t__gmt` and a response type `time_t`, but gets the message across how simple it is to build a Web service API. You can add as many functions and C/C++ data types as necessary to create new service APIs as described in the next section.
The default option for soapcpp2 is to generate both client and server code in `soapClient.c`[`pp`] and `soapServer.c`[`pp`], respectively. This assumes that SOAP (and/or REST) services are defined in a WSDL (or a WADL) that is input to wsdl2h to convert to the interface file file.h. If the input to wsdl2h consists XSD files only without a WSDL, then you can use the basic XML REST API. Skip further down to find out how to use the XML REST API.
### XML SOAP API
The `soapClient.c`[`pp`] and `soapServer.c`[`pp`] files are generated by soapcpp2 to implement the Web service API declared in an interface file, say file.h. Service API functions in file.h are of the form:
int prefix__func(arg1, arg2, ..., argn, result);
where `prefix` is associated with an XML namespace using a `//gsoap` directive, and the function has zero or more input arguments and one result argument that is usually a struct/class with multiple values:
//gsoap prefix service namespace: http://www.example.com
struct prefix__funcResponse { arg1; arg2; ... argk; };
int prefix__func(arg1, arg2, ..., argn, prefix__funcResponse*);
For these function definitions the soapcpp2 CLI invoked on the command line generates several source code files (which are .cpp files unless option `-c` is used to generate C):
- `soapClient.c`[`pp`] client-side stub functions
- `soapServer.c`[`pp`] server-side dispatch functions
- `soapC.c`[`pp`] XML serializers for all XML SOAP API function arguments
- `soapH.h` XML serializers and service API functions
- `soapStub.h` cleaned-up copy of the file.h declarations, this file is included by `soapH.h`
- `prefix.nsmap` XML namespace bindings table to #include in your code
Other files generated are sample XML messages, and WSDL and XSD files.
To invoke the service on the client side, the `soapClient.c`[`pp`] should be compiled together with your code so you can invoke the service as follows:
#include "soapH.h" // XML serializers and service API functions
#include "prefix.nsmap" // the soapcpp2-generated .nsmap file
struct soap *soap = soap_new(); // create a new context
if (soap_call_prefix__func(soap, "URL", "action", arg1, arg2, ..., argn, &result) == SOAP_OK)
... // use the result
else
... // error
soap_destroy(soap); // delete result and C++ instances managed by the context
soap_end(soap); // delete other managed data
soap_free(soap); // free the context
where `URL` is the Web service endpoint URL to connect to and `action` is a SOAP action header. The function returns `SOAP_OK` (zero) on success, or an error code on failure. When invoking the call, you can use NULL for the default URL and action set by the `//gsoap prefix service port:` and `//gsoap prefix service method-action:` directives that you can add to file.h.
To display an error returned by a call, use:
void soap_print_fault(struct soap*, FILE*);
void soap_stream_fault(struct soap*, std::ostream&);
As you can see, by convention gSOAP functions take the engine context `struct soap*` as the first argument and return `SOAP_OK` (zero) or an error code.
To build your clients and/or servers, you will need to compile `soapClient.c`[`pp`] (client-side), `soapServer.c`[`pp`] (server-side), `soapC.c`[`pp`] and `stdsoap2.c`[`pp`] (or link with the `libgsoap` library, see [overview of tools and libraries](#overview)).
The auto-generated `soapServer.c`[`pp`] source code by soapcpp2 for file.h implements a service dispatcher:
int soap_serve(struct soap*);
You can use this dispatcher directly to deploy CGI-hosted services or put it in a loop to accept incoming requests on a port (see the server examples in this article). You should also implement all of the service API functions declared in file.h but with an additional first argument:
int prefix__func(struct soap*, arg1, arg2, ..., argn, prefix__funcResponse *result)
{
// ... implement your service logic here
return SOAP_OK;
}
You can generate more powerful C++ proxy and service classes with soapcpp2 option `-j`. Otherwise, your C++ code will be similar to C code with stub functions and a service dispatcher. With option `-j`, the `NameProxy` class is saved in `soapNameProxy.h` and `soapNameProxy.cpp`. The `NameService` class is saved in `soapNameService.h` and `soapNameService.cpp`. The details of the auto-generated class-based APIs are saved in the proxy and service header files, which we will not describe in detail here, but that are used in the C++ client and server examples in this article.
We also recommend that you read about the examples below to understand how a [C++ client](#client-cpp) and a [C++ server](#server-cpp) are implemented (both with option `-j`), and how a [C client](#client-c) and a [C server](#server-c) are implemented.
This covers the basics of the XML SOAP API. For more details, please see the C and C++ client and server examples in this document, the [examples](examples/calc/index.html) provided on this web site, and the [gSOAP documentation](docs.html).
### XML REST API
You will need gSOAP 2.8.38 or greater for this new feature.
Implementing client-side functions to access an XML REST API is very simple. You can use this approach with or without XSD files. If you have a set of XSD files then run wsdl2h on these and then soapcpp2:
[command]
wsdl2h -o file.h ... XSD files or URLs to XSD files ...
soapcpp2 file.h
Use wsdl2h option `-c` for C code. For each XSD element or type *Type* with data binding *Name* in C or C++, the soapcpp2 CLI generates the following XML REST API functions for GET, PUT and POST:
int soap_GET_Name(struct soap*, const char *URL, Type*);
int soap_PUT_Name(struct soap*, const char *URL, const Type*);
int soap_POST_send_Name(struct soap*, const char *URL, const Type*);
int soap_POST_recv_Name(struct soap*, Type*);
int soap_PATCH_send_Name(struct soap*, const char *URL, const Type*);
int soap_PATCH_recv_Name(struct soap*, Type*);
The two POST functions should be called together, first a POST send to transmit XML data to the endpoint URL followed by a POST receive to accept the response data (may be of a different type). The same sequence applies to the PATCH functions.
If you do not have an XSD file, for example you want to implement a client and service XML REST API from scratch, then define C or C++ types in an interface header file.
For more details on this, see the [C++ REST client](#client-rest-cpp) and [C REST client](#client-rest-c) examples in this document.
To implement an XML REST API server requires the `httpget` and `httppost` plugins to be registered with a gSOAP server to accept GET, PUT, and POST requests. You don't need these for the client side.
[![To top](images/go-up.png) To top](#)
gSOAP XML data bindings {#bindings}
---
Our aim is to make XML very simple to use for developers of C and C++ applications. In fact, coding with XML is as easy as coding your C/C++ data structures. Your C and C++ data structures are simply serialized in XML and parsed from XML. No tedious low-level DOM coding. No slowdown with XML DOM parsers. No frustration with XML validation errors. Just use your data that is serialized to/from XML by an **XML data binding** that is auto-generated by our tools from XML schemas or WSDLs. Your software development and testing time will be significantly reduced.
The benefit of an XML data binding is that it glues XML schema types to C/C++ types and vice versa. So integers in XML are bound to C integers, strings in XML are bound to C or C++ strings, complex types in XML are bound to C structs or C++ classes, and so on. So we know for sure that the structured data you create and accept will fit the data model and is **static type safe**. In other words, by leveraging strong typing in C/C++, your XML data meets **XML validation requirements** and satisfies **XML interoperability requirements**.
Compared to other serialization formats, XML is truly open, extensible, interoperable, platform neutral, and verifiable with XSD data bindings. XML is a community effort organized by the W3C and is subject to rigorous standardization practices. XML also has several advantages over so-called "schemaless" data formats: XML schemas describe types, elements, and attributes with their properties to validate XML data efficiently. Validation gives us a **strong safety net** that ensures that invalid content is automatically rejected, before the data is processed by the application. XML schemas also allow us to build large and complex data structures and systems from schemas as building blocks, without having to worry about name and type clashes.
With our gSOAP tools you can efficiently and practically **serialize any application-specific data structures** in XML. Even **legacy C/C++ applications** can be converted by our tools to support XML serialization.
To learn more after reading this section, visit [XML data bindings.](doc/databinding/html/index.html)
### What is an XML data binding?
Consider the following example XML schema `hr.xsd` with an *`employee`* type defined in an *`HR`* schema namespace:
[xml]
This schema describes the following example XML document, also called an instance of the schema:
[xml]
An XML data binding for C/C++ maps schemas to C/C++ types and vice versa. The gSOAP XML data binding for this complex type in C++ is a `ns__employee` class:
#import "gsoap/import/stlvector.h" // import std::vector XML data binding
//gsoap ns schema namespace: HR
class ns__employee {
public:
@std::string name 1; // required name attribute
@int ID 0 = 9999; // optional ID attribute, defaults to 9999
std::vector manages 0:12; // up to 12 elements
};
This **data binding interface** in C/C++ is auto-generated from the example schema with the **wsdl2h** tool. But you can also declare your own interface to make your C/C++ types XML serializable and generate XML schemas for these. The wsdl2h CLI takes one ore more WSDL and/or XSD files or URLs to these files as command-line arguments:
[command]
wsdl2h -o hr.h hr.xsd
This generates the `hr.h` interface file with interface declarations and the `ns__employee` class shown above. The `ns__employee` class has a required name (`1` means that member occurs exactly once in XML content), an integer ID with default value `9999` which is used when the value is omitted (`0` means may be optional in XML content), and up to twelve employees whom he or she manages (`0:12` means up to 12 occurrences).
The pointers in the vector may not be strictly needed, but pointers can be useful for two main reasons. Firstly, you can serialize objects of base and derived classes via pointers. Secondly, you can serialize object graphs. That is, (cyclic) graphs are accurately serialized in XML using the context flag `SOAP_XML_GRAPH` or in SOAP-encoded format, otherwise all cycles will be cut by the gSOAP engine to serialize finite XML document trees.
Note the use of a prefix `ns` in the `ns__employee` class. We use this convention to bind XML namespace prefixes to C/C++ types, member names, and to Web service functions. A prefix is not absolutely required to serialize types in XML, but it is strongly recommended to ensure that the type is bound to a schema.
- a colon can be used to prefix names in data bindings. For example `ns:employee` instead of `ns__employee`. However, the colon notation cannot guarantee the absence of C/C++ name clashes caused by identical names defined in different XML namespaces (e.g. `ns:employee` clashes with `xy:employee` in C/C++, yet they are different tags in XML).
- the `//gsoap` directives and class member annotations are part of the data binding specification that is auto-generated from WSDLs and schemas with **wsdl2h**. These annotations are used to generate the **data binding implementation** code with **soapcpp2**. You can set various properties of the schema using [directives](https://www.genivia.com/doc/databinding/html/index.html#directives).
### Using XML data bindings
An XML data binding makes it easy to write code to read, write, and manipulate XML-sourced data. The binding allows you to populate and extract XML data by working on C/C++ data structures that are equivalent to schema structures. Therefore, the benefit of the gSOAP data binding is that you can work with native C/C++ types, thereby creating and accepting valid XML data that is static type safe in C/C++.
As an example, suppose we create a `boss` instance of the `ns__employee` class and add an employee to the list of employees that the boss manages, where the new employee is read from an XML file:
#include "soapH.h" // include auto-generated data bindings
#include "ns.nsmap" // include auto-generated XML namespaces
struct soap *soap = soap_new(); // a new gSOAP runtime engine context, for memory management, IO, etc.
ns__employee boss;
boss.name = "Jane Doe";
boss.ID = 123;
ns__employee temp;
soap_read_ns__employee(soap, &temp); // read temp XML data from stdin (auto-generated function)
boss.manages.push_back(&temp);
soap_write_ns__employee(soap, &boss); // write boss XML data to stdout (auto-generated function)
soap_destroy(soap); // delete managed C++ instances
soap_end(soap); // delete other data
soap_free(soap); // we're done
Use the **soapcpp2** tool on the data binding interface `hr.h` (that was shown earlier) to generate **data binding implementation** code with efficient **streaming XML serializers** for the C/C++ types in your application. Then compile the generated code `soapC.cpp` with the engine code `stdsoap2.cpp` (or link with `libgsoap++` together with the application code `hr.cpp`, e.g. on the command line:
[command]
soapcpp2 hr.h
c++ -o hr hr.cpp soapC.cpp stdsoap2.cpp
Here, the soapcpp2 CLI is executed on `hr.h` that was generated by wsdl2h from a schema. However, you can also execute the soapcpp2 CLI on your own interface file by declaring the C/C++ data types that you want to serialize and let soapcpp2 generate the schema together with the XML serializers.
The soapcpp2 CLI generates a set of functions for each serializable C/C++ type declared in the interface file. These functions use names that follow simple naming conventions, see e.g. auto-generated [operations on classes and structs.](https://www.genivia.com/doc/databinding/html/index.html#toxsd9-13). There are only a few auto-generated functions per serializable type that you will ever need to use, so you don't need to read in detail what is in the generated files `soapStub.h`, `soapH.h` and `soapC.cpp` that implement these functions for each serializable type.
The auto-generated functions to create, read, write, and deep copy and delete data for each C/C++ type declared in the data binding interface are illustrated below for the `ns__employee` class type:
// managed instantiation supporting automatic deletion
ns__employee *employee = soap_new_ns__employee(soap);
// instantiate and set only the required (as per schema) member(s)
ns__employee *employee = soap_new_req_ns__employee(soap, "Jane Doe");
// also std::string is a serializable type
std::string *name = soap_new_std__string(soap);
*name = "Jane Doe";
// instantiate and set all members of an employee
std::vector manages;
ns__employee *employee = soap_new_set_ns__employee(soap, name, 123, manages);
// write to std::cout via std::ostream* soap->os (std::istream* soap->is is for reading)
soap->os = &std::cout;
if (soap_write_ns__employee(soap, employee))
... // handle IO error
soap->os = NULL; // reset to use default streams
// read from a file via soap->recvfd (soap->sendfd is for writing)
soap->recvfd = open("employee.xml", O_RDONLY);
if (soap_read_ns__employee(soap, employee))
... // handle IO error
close(soap->recvfd);
soap->recvfd = 0; // reset to stdin
// deep copy employee to another managing context (soapcpp2 option -Ec to generate)
struct soap *other_soap = soap_new();
ns__employee *employee_copy = employee->soap_dup(other_soap);
// reset employee to default member values
employee->soap_default(soap);
// delete all objects managed by the context, must be called before soap_end(soap)
soap_destroy(soap);
// free all data allocated with soap_malloc/soap_new and internal data
soap_end(soap);
To serialize XML to strings and parse XML from strings you can set the C++ streams `soap->os` and `soap->is` to point to `std::stringstream` objects:
#include "soapH.h"
#include "ns.nsmap"
#include
std::stringstream ss;
struct soap *soap = soap_new();
// write to string via std::ostream* soap->os
soap->os = &ss;
if (soap_write_ns__employee(soap, employee))
... // handle IO error
soap->os = NULL;
... = ss.str();
// read from string via std::istream* soap->is
ss.str("...");
soap->is = &ss;
if (soap_read_ns__employee(soap, employee))
... // handle IO error
soap->is = NULL;
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
For gSOAP 2.8.28 and later, serializing XML to C `char*` strings and parsing XML from C strings and buffers is fairly easy. You can simply set `soap->os` to point to an output string and set `soap->is` to point to an input string to parse from:
#include "soapH.h"
#include "ns.nsmap"
struct soap *soap = soap_new();
// C string we want to set to the 0-terminated string with XML output
const char *cs = NULL;
soap->os = &cs;
if (soap_write_ns__employee(soap, employee))
... // handle IO error
soap->os = NULL;
... = cs; // use the string (do not free(cs): cs is managed by context and freed with soap_end())
// C string we want to read from
soap->is = "...";
if (soap_read_ns__employee(soap, employee))
... // handle IO error
soap->is = NULL;
soap_destroy(soap);
soap_end(soap);
soap_free(soap);
SOAP/XML and REST-XML service operations essentially work the same way and require very few lines of code to send and receive data serialized in XML. Most of the SOAP/XML processing logic and details are hidden, allowing you to focus on your application logic. Continue reading the next section to learn more.
The gSOAP tools also support JSON and XML-RPC data formats and services. See our [tutorials](tutorials.html) and [XML-RPC and JSON/JSONPath.](doc/xml-rpc-json/html/index.html)
To learn more about XML data bindings, see [XML data bindings.](doc/databinding/html/index.html)
To learn more about the tools and libraries, see the [overview of gSOAP tools and libraries.](#overview)
To get gSOAP, visit [download and installation.](downloads.html)
[![To top](images/go-up.png) To top](#)
How portable, fast, and big will my code be? {#performance}
---
The gSOAP toolkit supports a wide variety of platforms and is portable to Windows Win32/Win64 (XP, Vista, Windows 7/8/10), MS-DOS, Cygwin, MinGW, Linux (RedHat, SuSE, Debian, Ubuntu, CentOS, etc.), Unix (Mac OS X, Solaris, HP-UX, BSD, FreeBSD, Irix, QNX, AIX, TRU64), OpenVMS, NonStop Tandem, VxWorks, WinCE, Palm OS, Symbian, iOS, Raspberry Pi, and embedded systems/RTOS.
You can deploy your gSOAP C and C++ services as stand-alone Web servers or deploy them with [Apache modules](doc/apache/html/index.html) and with [IIS ISAPI.](doc/isapi/html/index.html) See our [tutorials](tutorials.html) on how to implement and deploy gSOAP Web services. Also CGI and FastCGI can be used to deploy your services. You can use [WinInet](doc/wininet/html/index.html) to develop Windows client applications. Or you can simply deploy stand-alone SOAP and RESTful services and clients with the built-in HTTP/S stack.
You can also leverage the gSOAP toolkit to deploy legacy C and C++ systems as modernized Web services with SaaS. The Web service API and WSDL service descriptions are auto-generated for you.
### Interoperable
Applications developed with gSOAP are interoperable with other SOAP and RESTful XML stacks such as .NET WCF, Axis, PHP5, SOAP::Lite, SOAP4R, Weblogic, ZSI and many others. Furthermore, XML data binding enables interoperable XML data processing in non-SOAP/REST environments. The assurance of interoperability is strong. The gSOAP toolkit participated early on in [SOAP interoperability](http://www.whitemesa.com/interop.htm) testing and in the more recent W3C XML Schema Patterns for Databinding Interoperability testing, where the gSOAP 2.8 releases pass all pattern tests.
The gSOAP toolkit meets W3C and OASIS standards requirements for WSDL, XSD, SOAP, RESTful XML, WS-I Basic and Security Profiles, WS-Policy, WS-SecurityPolicy, WS-Security, WS-Addressing, WS-ReliableMessaging, WS-Discovery, and passes W3C Databinding interoperability tests. The toolkit also includes libraries for XML-RPC and JSON.
### High performance
The gSOAP toolkit generates efficient XML serialization code for fast Web services and other XML applications. The serializers push and pull XML directly to and from sockets without the overhead of DOM or SAX or third-party HTTP and XML stacks. Also MIME/MTOM attachments can be streamed for efficient binary content transfers.
A SOAP/XML message throughput test with a stand-alone echo string SOAP service over HTTP on quad core Intel Core i7 1.8GHz machines gives a sustained performance of **5,600 service invocations per second**. That is **11,200 one-way messages per second**, with IPv4 and keep-alive enabled. With IPv6 the performance drops slightly to 4,500 service invocations per second. A stand-alone HTTP1.1 gSOAP server with keep-alive enabled is fast for two-way messaging. We observed that **the WebSockets protocol gave no speed improvement**.
When socket connections are established from scratch without connection persistence (i.e. no keep-alive), the performance is 2,230 service invocations per second. That is 4,460 one-way messages per second. Here, the TCP/IP connection overhead dominates the execution time. The throughput of SOAP-over-UDP messaging with gSOAP is similar. However, network and TCP/IP or UDP connection latencies will vary from system to system.
With HTTPS encryption and server authentication using a stand-alone gSOAP server with OpenSSL RSA 2048 bits, the sustained performance is 3,700 service invocations per second with HTTP keep-alive. Without connection persistence, i.e. each invocation demands a full TLS handshake and certificate authentication, 1,200 service invocations per second can be achieved which is still **less than 1ms to complete an HTTPS service invocation**.
### Small memory footprint
The memory footprint of a gSOAP application is typically low, with a very small footprints (a few KBs instead of MBs) for limited XML uses. The code size depends linearly on the size of the WSDL and/or XML schemas that are mapped to C/C++ types. Each serializable struct and class requires some extra code for default initialization, serialization, and deserialization.
You can generate a minimal slice of code with wsdl2h options -O2, -O3 or -O4. This "schema slicing" algorithm removes unused schema components that aren't required to develop services and client applications. For example, wsdl2h option -O4 removes as much as 70% of the schema components defined in ONVIF WSDLs on average, resulting in much more compact code.
A smaller stand-alone C client, such as a calculator or a stock quote ticker for example, is compiled with `-DWITH_LEANER` to only 94K of code (Linux/i386/GCC -O1), and uses only 4KB heap space, and a 3KB stack footprint. With standard non-lean compilation, these numbers are 142KB code, 5KB heap, and 66KB stack, where stack space is used for the engine context that includes a 64KB read/write buffer to optimize socket transfers.
The runtime memory usage depends on your application's runtime data, which includes the size of the C/C++ data serialized in XML. Your data is directly serialized in XML. There is no other significant memory overhead. Some stack or heap memory is used by the gSOAP engine context that has an internal IO buffer (the default 64K size of the buffer can be changed). Also, we make it very easy for you to [manage](doc/databinding/html/index.html#memory) your data in memory, including allocation, deep copy, and deallocation.
[![To top](images/go-up.png) To top](#)
Example XML SOAP client (C++) {#client-cpp}
---
Let's put the gSOAP tools to work to convert a simple example calculator WSDL to a working C++ client that invokes the calculator service:
[command]
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
The `calc.h` file includes the following declarations (showing only one operation here for brevity):
//gsoap ns2 schema namespace: urn:calc
//gsoap ns2 schema form: unqualified
//gsoap ns2 service name: calc
//gsoap ns2 service type: calcPortType
//gsoap ns2 service port: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi
//gsoap ns2 service namespace: urn:calc
//gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http
//gsoap ns2 service method-protocol: add SOAP
//gsoap ns2 service method-style: add rpc
//gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/
//gsoap ns2 service method-action: add ""
//gsoap ns2 service method-output-action: add Response
int ns2__add(
double a, // Input parameter
double b, // Input parameter
double &result // Output parameter
);
As you can see, gSOAP uses three basic forms of source code annotations in the auto-generated data binding interface file:
- [directives](doc/databinding/html/index.html#directives), such as `//gsoap ns2 schema namespace: urn:calc`
- [identifier naming conventions](doc/databinding/html/index.html#toxsd2), such as `ns2__add`
- other annotations (not shown in this example) for declaring XML attributes and for enforcing XML validation rules.
The directives in this example describe the Web service API properties of this calculator service: this is a SOAP RPC style messaging service over HTTP. Other possible protocols include REST protocols (POST, GET, PUT, and DELETE) and `SOAP-GET`.
Service operations are declared in the gSOAP interface file as functions with parameters that are all input arguments except for the last parameter, which is a reference (or a pointer for C) to the result. The result argument is set by the response data of the service. We selected this example because it has simple parameters to illustrate the operational aspects.
Next, you run the soapcpp2 CLI to generate the data binding implementation that "glues" your code to the service operations:
[command]
soapcpp2 -j -CL -I/path/to/gsoap/import calc.h
Option `-j` produces C++ proxy classes with `-CL` indicating client-side (non-libs), using an import path for the `#import` files in `calc.h`.
Several files are generated, among those are:
[command]
Saving soapStub.h annotated copy of the source input
Saving soapH.h declarations to #include
Saving soapcalcProxy.h client proxy class
Saving soapcalcProxy.cpp client proxy class
Saving calc.nsmap namespace mapping table
Saving soapC.cpp serializers
See the [calc++ example](examples/calc++/index.html) for more details and source code.
Use the generated proxy in your main program `calcclient.cpp` to invoke the calculator service:
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapcalcProxy.h" // the proxy class, also #includes "soapH.h" and "soapStub.h"
int main()
{
calcProxy calc;
double sum;
if (calc.add(1.23, 4.56, sum) == SOAP_OK)
std::cout << "Sum = " << sum << std::endl;
else
calc.soap_stream_fault(std::cerr);
calc.destroy(); // same as: soap_destroy(calc.soap); soap_end(calc.soap);
}
To compile the program and run it, execute on the command line:
[command]
c++ -o calcclient calcclient.cpp soapC.cpp soapcalcProxy.cpp stdsoap2.cpp
./calcclient
Sum = 5.79
It is highly recommended to change the `n2__` prefix that wsdl2h produced to something more maintainable. To do so, add the following line to `typemap.dat` that is used by wsdl2h (put `typemap.dat` in your build directory or use wsdl2h with option `-t/path/to/gsoap/typemap.dat`):
[command]
c = "urn:calc"
Then run wsdl2h again to generate a new `calc.h` file with the temporary default namespace prefix `ns2` permanently replaced by prefix `c`.
Finally, you may want to add timeouts to avoid the client from blocking on an unresponsive server:
calc.soap->connect_timeout = 10; // connect within 10s
calc.soap->send_timeout = 5; // send timeout is 5s
calc.soap->recv_timeout = 5; // receive timeout is 5s
if (calc.add(1.23, 4.56, sum) == SOAP_OK)
std::cout << "Sum = " << sum << std::endl;
Some systems (Linux) do no support connection timeouts.
To prevent connection reset errors (UNIX SIGPIPE), set one of these two:
calc.soap->socket_flags = MSG_NOSIGNAL;
calc.soap->accept_flags = SO_NOSIGPIPE;
or install a SIGPIPE handler:
void sigpipe_handle(int x) { }
signal(SIGPIPE, sigpipe_handle);
[![To top](images/go-up.png) To top](#)
Example XML SOAP client (C) {#client-c}
---
This simple example C client is similar to the C++ client described in the previous section. However, you cannot use a proxy class. Instead, you use an auto-generated client stub function to invoke the service.
Use wsdl2h option `-c` to generate pure C code:
[command]
wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
Next, execute soapcpp2 on `calc.h` on the command line to generate the data binding implementation:
[command]
soapcpp2 -CL calc.h
Several files are generated, among those are:
[command]
Saving soapStub.h annotated copy of the source input
Saving soapH.h declarations to #include
Saving calc.nsmap namespace mapping table
Saving soapClient.c client proxy class
Saving soapC.c serializers
See the [calc example](examples/calc/index.html) for more details and source code.
The generated "client stub function" `soap_ns2__add` defined in `soapClient.c` implements the interface function `ns2__add` that is declared in `calc.h`. Use this stub function to invoke the service:
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapH.h" // client stubs, serializers, etc.
int main()
{
struct soap *soap = soap_new(); // allocate and initialize a context
double sum;
if (soap_call_ns2__add(soap, NULL, NULL, 1.23, 4.56, &sum) == SOAP_OK)
printf("Sum = %g\n", sum);
else
soap_print_fault(soap, stderr);
soap_destroy(soap); // delete managed deserialized C++ instances
soap_end(soap); // delete other managed data
soap_free(soap); // free the soap struct context data
}
To compile the program and run it, execute on the command line:
[command]
cc -o calcclient calcclient.c soapC.c soapClient.c stdsoap2.c
./calcclient
Sum = 5.79
It is highly recommended to change the `n2__` prefix that wsdl2h produced to something more maintainable. To do so, add the following line to `typemap.dat` that is used by wsdl2h (put `typemap.dat` in your build directory or use wsdl2h option `-t/path/to/gsoap/typemap.dat`):
[command]
c = "urn:calc"
Then run wsdl2h with option `-c` (for C code) again to generate a new `calc.h` file with the temporary default namespace prefix `ns2` permanently replaced by prefix `c`.
Finally, you may want to add timeouts to avoid the client from blocking on an unresponsive server:
soap->connect_timeout = 10; // connect within 10s
soap->send_timeout = 5; // send timeout is 5s
soap->recv_timeout = 5; // receive timeout is 5s
if (soap_call_c__add(soap, NULL, NULL, 1.23, 4.56, &sum) == SOAP_OK)
std::cout << "Sum = " << sum << std::endl;
Some systems (Linux) do no support connection timeouts.
To prevent connection reset errors (UNIX SIGPIPE), set one of these:
soap->socket_flags = MSG_NOSIGNAL;
soap->accept_flags = SO_NOSIGPIPE;
or install a SIGPIPE handler:
void sigpipe_handle(int x) { }
signal(SIGPIPE, sigpipe_handle);
[![To top](images/go-up.png) To top](#)
Example XML SOAP server (C++) {#server-cpp}
---
For this simple example server we start with a WSDL file and execute wsdl2h on this file from the command line:
[command]
wsdl2h -o calc.h http://www.genivia.com/calc.wsdl
This command saves `calc.h`, declaring the interface to the calculator service. Here we only show one of the service operations with the other essential parts:
//gsoap ns2 schema namespace: urn:calc
//gsoap ns2 schema form: unqualified
//gsoap ns2 service name: calc
//gsoap ns2 service type: calcPortType
//gsoap ns2 service port: http://websrv.cs.fsu.edu/~engelen/calcserver.cgi
//gsoap ns2 service namespace: urn:calc
//gsoap ns2 service transport: http://schemas.xmlsoap.org/soap/http
//gsoap ns2 service method-protocol: add SOAP
//gsoap ns2 service method-style: add rpc
//gsoap ns2 service method-encoding: add http://schemas.xmlsoap.org/soap/encoding/
//gsoap ns2 service method-action: add ""
//gsoap ns2 service method-output-action: add Response
int ns2__add(
double a, // Input parameter
double b, // Input parameter
double &result // Output parameter
);
In addition to `ns2__add`, the service implements `ns2__sub`, `ns2__mul`, `ns2__div`, and `ns2__pow` functions with `double` parameters. We selected this example because it has simple parameters to illustrate the operational aspects.
It should be mentioned at this point that is perfectly possibly and easy to start developing services from a header file such as `calc.h` and generate WSDL files automatically. The soapcpp2 CLI does all the heavy lifting.
Next, we generate the server-side code and serializers using soapcpp2 on the command line:
[command]
soapcpp2 -j -SL -I/path/to/gsoap/import calc.h
Option `-j` produces C++ service classes. The option `-SL` indicates server-side (non-libs) and `-I` specifies an import path for the `#import` directives located in `calc.h` (if any).
Use the generated skeleton service class `calcService` that is declared in `soapcalcService.h` and defined in `soapcalcService.cpp`. The class declares the service operations as methods without actually implementing them. We implement the service operations in a new main program `calcserver.cpp`. We intent to deploy the service as a simple CGI-hosted service using the [Common Gateway Interface](http://en.wikipedia.org/wiki/Common_Gateway_Interface), which means you just need to call the `serve` method of the generated `calcService` class:
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapcalcService.h" // the service class, also #includes "soapH.h" and "soapStub.h"
int main()
{
calcService calc(SOAP_XML_INDENT);
if (calc.serve() != SOAP_OK)
calc.soap_stream_fault(std::cerr);
calc.destroy(); // same as: soap_destroy(calc.soap); soap_end(calc.soap);
}
int calcService::add(double a, double b, double &result)
{
result = a + b;
return SOAP_OK;
}
int calcService::sub(double a, double b, double &result)
{
result = a - b;
return SOAP_OK;
}
int calcService::mul(double a, double b, double &result)
{
result = a * b;
return SOAP_OK;
}
int calcService::div(double a, double b, double &result)
{
if (b == 0.0)
{
char *msg = (char*)soap_malloc(this->soap, 1024);
snprintf(msg, 1024, "Trying to divide %f by zero", a);
return this->soap_senderfault(msg, NULL);
}
result = a / b;
return SOAP_OK;
}
int calcService::pow(double a, double b, double &result)
{
result = ::pow(a, b);
// soap_errno is like errno, but compatible with Win32
if (soap_errno == EDOM)
{
char *msg = (char*)soap_malloc(this->soap, 1024);
snprintf(msg, 1024, "Can't take power of %f to %f", a, b);
return this->soap_senderfault("Power function domain error", msg);
}
return SOAP_OK;
}
Note that you can use `soap_malloc` to malloc data that will be automatically released when the service is done. For class instances, use the auto-generated `soap_new_X(this->soap)` functions to allocate objects of a class `X` that will be deallocated after the service responded.
Here are some examples on how to create temporary data managed by the `soap` engine context and to set default values:
// allocate N bytes (managed by the 'soap' context)
char *str = soap_malloc(soap, N);
// duplicate a char string (managed by the 'soap' context)
char *dup = soap_dup(soap, str);
// instantiate one object X (managed by the 'soap' context)
X *object = soap_new_X(soap);
// instantiate an array of N objects X (managed by the 'soap' context)
X *objects = soap_new_X(soap, N);
// instantiate and set only the required (as per schema) members m1, ..., mk (managed by the 'soap' context)
X *object = soap_new_req_X(soap, m1, m2, ..., mk);
// instantiate and set all members m1, ..., mk (managed by the 'soap' context)
X *object = soap_new_set_X(soap, m1, m2, ..., mk);
// reset object to default member values
object->soap_default_X(soap);
After sending the Web service response, invoke `calc.destroy()` as shown in the `calcservice.cpp` code above. This calls `soap_destroy(this->soap)` and `soap_end(this->soap)` to delete context-managed objects and temporary data, respectively.
Let's compile the program `calcserver.cpp` together with the auto-generated `soapcalcService.cpp` and `soapC.cpp` XML data bindings. Then we run it on the request message `calc.add.req.xml` that was auto-generated by soapcpp2 in the previous step:
[command]
c++ -o calcserver calcserver.cpp soapC.cpp soapcalcService.cpp stdsoap2.cpp
./calcserver < calc.add.req.xml
Status: 200 OK
Server: gSOAP/2.8
Content-Type: text/xml; charset=utf-8
Content-Length: 466
Connection: close
0
To host the service on the Web with CGI, install `calcserver` in `cgi-bin` on your Web server and set the permissions appropriately (this won't work if the file permissions are wrong or if CGI is not enabled). For FastCGI, compile the generated source code and `stdsoap2.cpp` with `-DWITH_FASTCGI`.
To host the service as a stand-alone HTTP server, change the main program to invoke the `run` method with a port number as follows:
int main()
{
calcService calc(SOAP_XML_INDENT);
if (calc.run(8080) != SOAP_OK)
calc.soap_stream_fault(std::cerr);
calc.destroy();
}
This runs the service as an iterative Web server on port 8080, but any error will terminate it.
You may want to put this in an infinite loop to restart a `run()` on the same port. You also may want to add timeouts to avoid the server from blocking on an unresponsive client:
calc.soap->send_timeout = 5; // send timeout is 5s
calc.soap->recv_timeout = 5; // receive timeout is 5s
while (calc.run(8080) != SOAP_OK && calc.error != SOAP_TCP_ERROR)
calc.soap_stream_fault(std::cerr);
To prevent connection reset errors (UNIX SIGPIPE), set one of these:
calc.soap->socket_flags = MSG_NOSIGNAL;
calc.soap->accept_flags = SO_NOSIGPIPE;
or install a SIGPIPE handler:
void sigpipe_handle(int x) { }
signal(SIGPIPE, sigpipe_handle);
When deploying the service as a stand-alone Web server, we strongly recommend multi-threaded stand-alone services invoking the `bind()` method followed by a loop that invokes the `accept()` method to wait for a request and then creates a thread that invokes the `serve()` method. Also use reasonably short IO timeouts to harden your services, see [tutorials](tutorials.html) for details on how to implement and deploy gSOAP Web services.
See the [calc++ example](examples/calc++/index.html) for more details and source code.
You can also deploy gSOAP services as fast and robust [Apache modules](doc/apache/html/index.html) and [ISAPI extensions.](doc/isapi/html/index.html)
[![To top](images/go-up.png) To top](#)
Example XML SOAP server (C) {#server-c}
---
For implementing a C service similar to the C++ service described in the previous section we cannot use a service class. Instead, use wsdl2h option `-c` to generate pure C code:
[command]
wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
This command saves `calc.h`, declaring the interface to the calculator service, which is similar to the [C++ server](#server-cpp) example `calc.h` file.
It should be mentioned at this point that is perfectly possibly and easy to start developing services from a header file such as `calc.h` and generate WSDL files automatically. The soapcpp2 CLI does all the heavy lifting.
Next we run soapcpp2 on the `calc.h` file using option `-SL` to generate a server (no libs):
[command]
soapcpp2 -S -L calc.h
Several files are generated, among those are:
[command]
Saving soapStub.h annotated copy of the source input
Saving soapH.h declarations to #include
Saving calc.nsmap namespace mapping table
Saving soapServer.c server request dispatcher
Saving soapC.c serializers
The C implementation of the service requires us to define five global functions for the service operations, exactly as the `calc.h` file shows but now we add a parameter `soap` to each function to pass the context to this function:
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapH.h" // server stubs, serializers, etc.
int main()
{
struct soap *soap = soap_new1(SOAP_XML_INDENT);
if (soap_serve(soap) != SOAP_OK)
soap_print_fault(soap, stderr);
soap_destroy(soap); // delete managed deserialized C++ instances
soap_end(soap); // delete other managed data
soap_free(soap); // free the soap struct context data
}
int ns2__add(struct soap *soap, double a, double b, double *result)
{
*result = a + b;
return SOAP_OK;
}
int ns2__sub(struct soap *soap, double a, double b, double *result)
{
*result = a - b;
return SOAP_OK;
}
int ns2__mul(struct soap *soap, double a, double b, double *result)
{
*result = a * b;
return SOAP_OK;
}
int ns2__div(struct soap *soap, double a, double b, double *result)
{
if (b == 0.0)
{
char *msg = (char*)soap_malloc(soap, 1024);
snprintf(msg, 1024, "Trying to divide %f by zero", a);
return soap_sender_fault(soap, msg, NULL);
}
*result = a / b;
return SOAP_OK;
}
int ns2__pow(struct soap *soap, double a, double b, double *result)
{
*result = ::pow(a, b);
// soap_errno is like errno, but compatible with Win32
if (soap_errno == EDOM)
{
char *msg = (char*)soap_malloc(soap, 1024);
snprintf(msg, 1024, "Can't take power of %f to %f", a, b);
return soap_sender_fault(soap, "Power function domain error", s);
}
return SOAP_OK;
}
Note the use of `soap_malloc` to allocate a temporary message string.
Here are some examples on how to create temporary data managed by the `soap` engine context and to set default values:
// allocate N bytes (managed by 'soap' context)
char *str = soap_malloc(soap, N);
// duplicate a char string (managed by 'soap' context)
char *dup = soap_dup(soap, str);
// allocate struct X initialized (managed by 'soap' context)
struct X *object = soap_new_X(soap, 1);
// allocate array of N struct X initialized (managed by 'soap' context)
struct X *object = soap_new_X(soap, N);
// allocate struct X raw bytes without initialization (managed by 'soap' context)
struct X *object = soap_malloc(soap, sizeof(struct X));
// initialize struct X to default
soap_default_X(soap, object);
After sending the Web service response, call `soap_destroy(soap)` and `soap_end(soap)` to delete all context-managed objects and data, respectively.
Let's compile the program `calcserver.c` together with the auto-generated `soapService.c` and `soapC.cpp` XML data bindings. Then we run it on the request message `calc.add.req.xml` that was auto-generated by soapcpp2 in the previous step:
[command]
cc -o calcserver calcserver.c soapC.c soapcalcService.c stdsoap2.c
./calcserver < calc.add.req.xml
Status: 200 OK
Server: gSOAP/2.8
Content-Type: text/xml; charset=utf-8
Content-Length: 466
Connection: close
0
To host the service on the Web with CGI, install `calcserver` in `cgi-bin` on your Web server and set the permissions appropriately (this won't work if the file permissions are wrong or if CGI is not enabled). For FastCGI, compile the generated source code and `stdsoap2.c` with `-DWITH_FASTCGI`.
To host the service as a stand-alone HTTP server, change the main program:
int main()
{
struct soap *soap = soap_new1(SOAP_XML_INDENT);
if (!soap_valid_socket(soap_bind(soap, NULL, 8080, 10))) // port 8080 and small BACKLOG queue for iterative servers
exit(EXIT_FAILURE);
while (soap_valid_socket(soap_accept(soap)))
{
if (soap_serve(soap) != SOAP_OK)
break;
soap_destroy(soap); // delete deserialized C++ instances
soap_end(soap); // delete other managed data
}
soap_print_fault(soap, stderr);
soap_free(soap); // free the soap struct context data
}
This runs the service as an iterative Web server on port 8080 with a small backlog queue of 10 concurrent requests.
You may want to add timeouts to avoid the server from blocking on an unresponsive client:
soap->send_timeout = 5; // send timeout is 5s
soap->recv_timeout = 5; // receive timeout is 5s
if (!soap_valid_socket(soap_bind(soap, NULL, 8080, 10)))
... // error
To prevent connection reset errors (UNIX SIGPIPE), set one of these:
soap->socket_flags = MSG_NOSIGNAL;
soap->accept_flags = SO_NOSIGPIPE;
or install a SIGPIPE handler:
void sigpipe_handle(int x) { }
signal(SIGPIPE, sigpipe_handle);
When deploying the service as a stand-alone Web server, we strongly recommend multi-threaded stand-alone services that call `soap_bind()`, followed by a loop to call `soap_accept()` to wait for a request and then creates a thread that executes `soap_serve()`. Also recommended is to use reasonably short IO timeouts to harden your services. See [tutorials](tutorials.html) for details on how to implement and deploy gSOAP Web services with a choice of configurations.
See the [calc example](examples/calc/index.html) for details and source code.
You can also deploy gSOAP services as fast and robust [Apache modules](doc/apache/html/index.html) and [ISAPI extensions.](doc/isapi/html/index.html)
[![To top](images/go-up.png) To top](#)
Example AWS S3 SOAP API client (C++) {#aws}
---
This is a more advanced example of a stand-alone C++ client application for the AWS S3 API.
You can generate the data binding interface file for AWS S3 API from the AWS S3 WSDL with wsdl2h. Then use soapcpp2 to generate the client-side (soapcpp2 option `-C`) data binding implementation with a C++ proxy class (soapcpp2 option `-j`):
[command]
wsdl2h -t typemap.dat -o aws-s3.h http://doc.s3.amazonaws.com/2006-03-01/AmazonS3.wsdl
soapcpp2 -C -j aws-s3.h
The example C++ stand-alone AWS S3 client application [aws-s3.cpp](files/aws-s3.cpp) uses the generated `soapAmazonS3SoapBindingProxy.h` and namespace mapping table:
#include "soapAmazonS3SoapBindingProxy.h"
#include "AmazonS3SoapBinding.nsmap"
We add a convenient template function to allocate primitive values on the managed heap using `soap_malloc()` with context `soap`:
// Make allocation and assignment of primitive values quick and easy:
template
T * soap_make(struct soap *soap, T val = T())
{
T *p = (T*)soap_malloc(soap, sizeof(T));
*p = val;
return p;
}
We should only use this template to allocate and initialize primitive types. Structs and classes should be allocated with `soap_new_X`. This template simplifies coding to allocate and assign a value to a primitive type pointer, for example to assign a primitive value to a pointer member as shown further below.
Similarly, to allocate and set a `std::string` value:
// Make allocation and assignment of std::string quick and easy:
std::string * soap_make_string(struct soap *soap, const char *s = "")
{
std::string *p = soap_new_std__string(soap);
*p = s;
return p;
}
The main program instantiates a proxy to invoke the AWS S3 API and populates the argument `arg` of the `ListAllMyBuckets` service operation method by using the template we created above and the auto-generated allocation functions:
int main(int argc, char **argv)
{
// Create a proxy to invoke AWS S3 services
AmazonS3SoapBindingProxy aws(SOAP_XML_INDENT);
// Set the argument of the ListAllMyBuckets service operation
_s3__ListAllMyBuckets arg;
arg.AWSAccessKeyId = soap_make_string(aws.soap, argc > 1 ? argv[1] : "..."); // use your access key
arg.Timestamp = soap_make(aws.soap, time(0));
arg.Signature = soap_make_string(aws.soap, argc > 2 ? argv[2] : "..."); // use your signature
// Store the result of the service
_s3__ListAllMyBucketsResponse response;
// Get list of my buckets
if (aws.ListAllMyBuckets(&arg, response))
aws.soap_stream_fault(std::cerr);
else if (response.ListAllMyBucketsResponse)
{
s3__ListAllMyBucketsResult &result = *response.ListAllMyBucketsResponse;
s3__CanonicalUser *owner = result.Owner;
if (owner)
std::cout << "ID = " << owner->ID << std::endl;
if (owner && owner->DisplayName)
std::cout << "DisplayName = " << *owner->DisplayName << std::endl;
s3__ListAllMyBucketsList *buckets = result.Buckets;
if (buckets)
{
for (std::vector::const_iterator it = buckets->Bucket.begin(); it != buckets->Bucket.end(); ++it)
{
s3__ListAllMyBucketsEntry *entry = *it;
if (entry)
std::cout << "Name = " << entry->Name << " created " << soap_dateTime2s(aws.soap, entry->CreationDate) << std::endl;
}
}
}
// Delete all managed data
aws.destroy();
return 0;
}
As you can see, the proxy has an internal managing context `aws.soap` that we conveniently used to allocate managed data such as `std::string` with `soap_new_std__string(aws.soap)`. After the service invocation with `aws.ListAllMyBuckets` the result is displayed if the request was successful.
This example demonstrates one API operation only. To add more service invocations, see the [AWS S3 SOAP API report](examples/aws/index.html) that was generated with soapcpp2 option `-r` for the `aws-s3.h` interface file.
To compile the code from the command line we must use OpenSSL because the AWS S3 service requires HTTPS to ensure that the credentials are securely transmitted:
[command]
c++ -DWITH_OPENSSL -o aws-s3 aws-s3.cpp soapAmazonS3SoapBindingProxy.cpp \
soapC.cpp stdsoap2.cpp -lssl -lcrypto
For client-side connection timeouts, please see the example [client](#client-cpp) above.
To learn more about memory management in gSOAP, see [memory management.](doc/databinding/html/index.html#memory)
[![To top](images/go-up.png) To top](#)
Example XML REST API (C++) {#client-rest-cpp}
---
To use these new features for REST APIs, gSOAP 2.8.38 or greater is required.
This REST example uses PUT, GET, POST, DELETE to update a record. For an overview, see [Web services.](#services)
Suppose we have an XSD schema that defines the XML used by a REST API. The following file.h data binding interface file that was generated from this XSD schema by wsdl2h:
#import "custom/struct_tm_date.h" // custom xsd:date serializer for struct tm
class Person {
public:
std::string name;
xsd__date dob; // struct tm serialized as xsd:date
enum Gender { MALE, FEMALE } gender;
};
Note that this data binding has no XML namespaces. When XML namespaces are used with XML REST messaging, then you will notice that C++ identifiers are prefixed with a `ns1__` prefix. A `//gsoap` directive is used to bind the prefixes to XML namespace URIs for soapcpp2 to generate the data binding implementation and serializers.
Run soapcpp2 on this data binding interface file as follows:
[command]
soapcpp2 -0 file.h
This generates soapStub.h, soapH.h, soapC.cpp and soap.nsmap (you may get a different .nsmap file). The `-0` option removes the SOAP namespaces from the generated .nsmap file since we use REST instead of SOAP.
These generated files are needed to compile a client application. The soapcpp2 CLI generates several functions for each data type declared in file.h. This includes `soap_PUT_Name`, `soap_POST_send_Name`, `soap_POST_recv_Name`, `soap_PATCH_send_Name`, `soap_PATCH_recv_Name` and `soap_GET_Name` functions for type `Name` to invoke XML REST methods.
An example XML REST client application that executes PUT, GET, POST and DELETE methods with the `Person` data is:
#include "soapH.h"
#include "soap.nsmap"
int main()
{
soap *ctx = soap_new1(SOAP_XML_STRICT | SOAP_IO_CHUNK);
Person p;
// example PUT
p.name = "John Doe";
p.dob.tm_year = 66; // 1966 (year since 1900)
p.dob.tm_mon = 0; // month 0..11
p.dob.tm_mday = 31;
p.gender = MALE;
if (soap_PUT_Person(ctx, "http://example.com/person?john", &p))
soap_print_fault(ctx, stderr);
// example POST
if (soap_POST_send_Person(ctx, "http://example.com/person?john", &p)
|| soap_POST_recv_Person(ctx, &p))
soap_stream_fault(ctx, std::cerr);
else
soap_write_Person(ctx, &p); // display Person on stdout (default output)
// example GET
if (soap_GET_Person(ctx, "http://example.com/person?john", &p))
soap_stream_fault(ctx, std::cerr);
else
soap_write_Person(ctx, &p); // display Person on stdout (default output)
// DELETE
if (soap_DELETE(ctx, "http://example.com/person?john"))
soap_stream_fault(ctx, std::cerr);
soap_destroy(ctx); // delete managed and deserialized C++ instances
soap_end(ctx); // delete other managed data
soap_free(ctx); // we're done
return 0;
}
Note that POST requires two operations, one to send and one to receive data. The types of data you may want to send and receive can differ. But you MUST invoke a POST receive after a POST send.
To build the XML REST API client, compile the client C++ code together with soapC.cpp, custom/struct_tm_date.c and stdsoap2.cpp.
To build an XML REST server in C++ you will need to follow the instructions on building a stand-alone gSOAP server and use the httpget and httppost plugins. See also the gsoap/samples/rest directory in the gSOAP distribution package for details.
Note that we have not set any connection timeouts in this example or prevent SIGPIPE. For client-side connection timeouts and SIGPIPE handling, please see the relevant code in the example [SOAP client](#client-cpp). See our [tutorials](tutorials.html) for other options.
[![To top](images/go-up.png) To top](#)
Example XML REST API (C) {#client-rest-c}
---
To use these new features for REST APIs, gSOAP 2.8.38 or greater is required.
This REST example uses PUT, GET, POST, DELETE to update a record. For an overview, see [Web services.](#services)
Suppose we have an XSD schema that defines the XML used by a REST API. The following file.h data binding interface file that was generated from this XSD schema by wsdl2h:
#import "custom/struct_tm_date.h" // custom xsd:date serializer for struct tm
struct Person {
char *name;
xsd__date dob; // struct tm serialized as xsd:date
enum Gender { MALE, FEMALE } gender;
};
Note that this data binding has no XML namespaces. When XML namespaces are used with XML REST messaging, then you will notice that C identifiers are prefixed with a `ns1__` prefix. A `//gsoap` directive is used to bind the prefixes to XML namespace URIs for soapcpp2 to generate the data binding implementation and serializers.
Run soapcpp2 on this data binding interface file as follows:
[command]
soapcpp2 -c -0 file.h
This generates soapStub.h, soapH.h, soapC.c and soap.nsmap (you may get a different .nsmap file). The `-0` option removes the SOAP namespaces from the generated .nsmap file since we use REST instead of SOAP.
These generated files are needed to compile a client application. The soapcpp2 CLI generates several functions for each data type declared in file.h. This includes `soap_PUT_Name`, `soap_POST_send_Name`, `soap_POST_recv_Name`, `soap_PATCH_send_Name`, `soap_PATCH_recv_Name` and `soap_GET_Name` functions for type `Name` to invoke XML REST methods.
An example XML REST client application that executes PUT, GET, POST and DELETE methods with the `Person` data is:
#include "soapH.h"
#include "soap.nsmap"
int main()
{
struct soap *ctx = soap_new1(SOAP_XML_STRICT | SOAP_IO_CHUNK);
struct Person p;
// example PUT
p.name = "John Doe";
p.dob.tm_year = 66; // 1966 (year since 1900)
p.dob.tm_mon = 0; // month 0..11
p.dob.tm_mday = 31;
p.gender = MALE;
if (soap_PUT_Person(ctx, "http://example.com/person?john", &p))
soap_print_fault(ctx, stderr);
// example POST
if (soap_POST_send_Person(ctx, "http://example.com/person?john", &p)
|| soap_POST_recv_Person(ctx, &p))
soap_print_fault(ctx, stderr);
else
soap_write_Person(ctx, &p); // display Person on stdout (default output)
// example GET
if (soap_GET_Person(ctx, "http://example.com/person?john", &p))
soap_print_fault(ctx, stderr);
else
soap_write_Person(ctx, &p); // display Person on stdout (default output)
// example DELETE
if (soap_DELETE(ctx, "http://example.com/person?john"))
soap_print_fault(ctx, stderr);
soap_destroy(ctx); // delete managed and deserialized C++ instances
soap_end(ctx); // delete other managed data
soap_free(ctx); // we're done
return 0;
}
Note that POST requires two operations, one to send and one to receive data. The types of data you may want to send and receive can differ. But you MUST invoke a POST receive after a POST send.
To build the XML REST API client, compile the client C code together with soapC.c, custom/struct_tm_date.c and stdsoap2.c.
To build an XML REST server in C you will need to follow the instructions on building a stand-alone gSOAP server and use the httpget and httppost plugins. See also the gsoap/samples/rest directory in the gSOAP distribution package for details.
Note that we have not set any connection timeouts in this example or prevent SIGPIPE. For client-side connection timeouts and SIGPIPE handling, please see the relevant code in the example [SOAP client](#client-cpp). See our [tutorials](tutorials.html) for other options.
[![To top](images/go-up.png) To top](#)
Example GitHub JSON REST API v3 client (C++) {#git}
---
This example uses the [GitHub REST API v3](http://developer.github.com/v3) for JSON.
The gSOAP toolkit also offers a comprehensive [XML-RPC and JSON/JSONPath](doc/xml-rpc-json/html/index.html) API for C and C++. This includes a new code generator **jsoncpp** (gSOAP 2.8.26 and later) to generate JSON and JSONPath code for your projects.
To start from scratch, create a project directory and copy the gSOAP JSON API and XML-RPC API files to your project, together with the gSOAP engine source code (or link with libgsoapssl++.a):
[command]
cp gsoap/samples/xml-rpc-json/json.h .
cp gsoap/samples/xml-rpc-json/json.cpp .
cp gsoap/samples/xml-rpc-json/xml-rpc.h .
cp gsoap/samples/xml-rpc-json/xml-rpc-iters.h .
cp gsoap/samples/xml-rpc-json/xml-rpc.cpp .
cp gsoap/stdsoap2.h .
cp gsoap/stdsoap2.cpp .
Then generate the C++ XML-RPC data binding implementation code, which is also used by the JSON API (e.g. for memory management and other functions):
[command]
soapcpp2 -CSL xml-rpc.h
This generates soapStub.h, soapH.h, and soapC.cpp. Alternatively, you can put the gSOAP JSON API files and functions in a C++ namespace as discussed [here](doc/xml-rpc-json/html/index.html#json-cc).
The client application makes a JSON REST call (HTTP POST) to retrieve GitHub repository information as follows:
#include "json.h"
struct Namespace namespaces[] = { {NULL, NULL} }; // no XML namespaces needed
int main(int argc, char **argv)
{
if (argc >= 2)
{
// new context with JSON indentation formatting (same as XML indent)
soap *ctx = soap_new1(SOAP_C_UTFSTRING | SOAP_XML_INDENT);
// create a value for the GitHub API response
value response(ctx);
// private repos require authentication (should check that we use HTTPS!)
if (argc > 3)
{
ctx->userid = argv[2];
ctx->passwd = argv[3];
}
// JSON REST call and show response if OK (returns SOAP_OK (0) or error code)
if (json_call(ctx, argv[1], NULL, &response))
soap_stream_fault(ctx, std::cerr);
else
std::cout << response;
std::cout << "\n\nOK\n";
soap_destroy(ctx); // delete managed C++ instances
soap_end(ctx); // delete other managed data
soap_free(ctx); // delete context
}
return 0;
}
To compile the GitHub API client from the command line:
[command]
c++ -DWITH_OPENSSL -DWITH_GZIP -o json-GitHub json-GitHub.cpp \
xml-rpc.cpp json.cpp stdsoap2.cpp soapC.cpp -lcrypto -lssl -lz
Let's it out:
[command]
./json-GitHub https://api.github.com/orgs/Genivia/repos
For client-side connection timeouts, please see the example [client](#client-cpp) above.
To learn more about the gSOAP JSON API for C and C++, see the [tutorials](tutorials.html) and [XML-RPC and JSON/JSONPath](doc/xml-rpc-json/html/index.html) documentation.
[![To top](images/go-up.png) To top](#)
Selection of books featuring gSOAP {#books}
---
[![To top](images/go-up.png) To top](#)
Selection of articles on gSOAP {#articles}
---
See our [articles](articles.html) for more articles on gSOAP published in peer-reviewed venues.
[![To top](images/go-up.png) To top](#)