JSON current time client & server example
=========================================
Overview
--------
This example implements a simple JSON REST API client and server in C.
For more information about the use of JSON in gSOAP, see the [JSON documentation.](../../doc/xml-rpc-json/html/index.html)
Implementing the client application
-----------------------------------
The client application [`currentTime.c`](currentTime.c) is run at the command line and displays the current time:
    #include "json.h"
    int main()
    {
      struct soap *ctx = soap_new1(SOAP_C_UTFSTRING | SOAP_XML_INDENT);
      struct value *request = new_value(ctx);
      struct value response;
      ctx->send_timeout = 10; /* 10 sec, stop if server is not accepting msg */
      ctx->recv_timeout = 10; /* 10 sec, stop if server does not respond in time */
      /* make the JSON REST POST request and get response */
      *string_of(request) = "getCurrentTime";
      if (json_call(ctx, "http://localhost:8080", request, &response))
        soap_print_fault(ctx, stderr);
      else if (is_string(&response)) /* JSON does not support a dateTime value: this is a string */
        printf("Time = %s\n", *string_of(&response));
      else /* error? */
      {
        printf("Error: ");
        json_write(ctx, &response);
      }
      /* clean up */
      soap_destroy(ctx);
      soap_end(ctx);
      soap_free(ctx);
      return 0;
    }
    /* Don't need a namespace table. We put an empty one here to avoid link errors */
    struct Namespace namespaces[] = { {NULL, NULL} };
The JSON request message is the string `"getCurrentTime"` that is POSTed to the server.  The response is a string with the current time in UTC.
The context `ctx` is initialized with `SOAP_C_UTFSTRING` to ensure 8-bit strings contain Unicode in UTF-8 format.  The `SOAP_XML_INDENT` flag is optional, it displays JSON with an indented layout (just as XML is indented with this flag).
The `struct value` data represents a JSON value (and in fact also an XML-RPC value).
The JSON API is called with `json_call(ctx, "URL", request, &response)` using an HTTP POST because both input and output parameters are non-NULL.
The call `json_call(ctx, "URL", in, out))` with pointers `in` and `out` to JSON values supports HTTP POST (both `in` and `out` are non-NULL), HTTP GET (`in` is NULL, `out` is non-NULL), HTTP PUT (`in` is non-NULL, `out` is NULL), and HTTP DELETE (`in` and `out` are NULL).
JSON values can be read with `json_read(ctx, v)` with pointer `v` to an (empty) JSON value that will be assigned. To read from a file descriptor, set the context `ctx->recvfd` to the descriptor. To read from a string, set the context `ctx->is` to a `char*` string which works in C only. In C++ set the context `ctx->is` input stream to a string stream.
JSON values can be written with `json_write(ctx, v)` with pointer `v` to a JSON value that will be saved. To write to a file descriptor, set the context `ctx->sendfd` to the descriptor. To write to a string, set the context `ctx->os` to point to a `char*` to be assigned with the string saved, which works in C only. In C++ set the context `ctx->os` output stream to a string stream.
An empty request value is created with `new_value(ctx)`. The response JSON value is a string that is verified with `is_string(&response)` and the string value is obtained with `string_of(&response)`.
A JSON value `v` can be assigned a choice of value types:
    *int_of(v) = 12345LL;    /* 64 bit int */
    *double_of(v) = 12.34;   /* double float */
    *string_of(v) = "abc";   /* string */
    *string_of(v) = soap_wchar2s(ctx, L"xyz"); /* wide string (converted to UTF-8) */
    *bool_of(v) = 0;         /* Boolean false (0) or true (1) */
    *dateTime_of(v) = soap_dateTime2s(ctx, time(0));
                             /* time_t value serialized as ISO 8601 date time */
    /* create an array [24, 99.99, "abc"] */
    *int_of(nth_value(v, 0)) = 24;
    *double_of(nth_value(v, 1)) = 99.99;
    *string_of(nth_value(v, 2)) = "abc";
    /* create object {"name": "gsoap", "major": 2.8, "©": 2015} */
    *string_of(value_at(v, "name")) = "gsoap";
    *double_of(value_at(v, "major")) = 2.8;
    *int_of(value_atw(v, L"©")) = 2015;  /* wide string properties are OK */
These functions are also used to retrieve values.  For example
    int n = *int_of(v);
which takes or converts the JSON value `v` to an integer.  Before taking or converting a JSON value, you may want to check its type:
    is_null(v)     /* true if value is not set (JSON null) */
    is_bool(v)     /* true if value is a Boolean "true" or "false" value */
    is_true(v)     /* true if value is Boolean "true" */
    is_false(v)    /* true if value is Boolean "false" */
    is_number(v)   /* true if value is a number (int or float) */
    is_int(v)      /* true if value is a 32 or a 64 bit int */
    is_double(v)   /* true if value is a 64 bit double floating point (not integer) */
    is_string(v)   /* true if value is a string */
    is_array(v)    /* true if array of values */
    is_struct(v)   /* true if object structure */
The following functions can be used with JSON arrays and objects:
    void set_struct(v)                         /* reset/create an empty object structure */
    void set_size(v, int)                      /* reset/change array size or pre-allocate space */
    int has_size(v)                            /* returns array or object structure size or 0 */
    struct value *nth_value(v, int)            /* returns nth value in array or object structure */
    struct value *value_at(v, const char*)     /* returns property value of object structure */
    struct value *value_atw(v, const wchar_t*) /* returns property value of object structure */
    int nth_at(v, const char*)                 /* returns nth index of property of object or -1 */
    int nth_atw(v, const wchar_t*)             /* returns nth index of property of object or -1 */
    int nth_nth(v, int)                        /* returns nth index if nth index exists in array or -1 */
See the [JSON documentation](../../doc/xml-rpc-json/html/index.html) for more details on the JSON functions to create, inspect, and retrieve values.
For more information about authentication and HTTPS, see the [tutorials.](../../tutorials.html)
Also see the [tutorials](../../tutorials.html) on how to set timeouts and handle signals.
[ To top](#)
Build steps for the client application
--------------------------------------
The use of JSON requires a one-time step to generate a data model that supports both JSON and the older XML-RPC protocols:
    [command]
    soapcpp2 -c -CSL xml-rpc.h
The `xml-rpc.h` file and all other source code files that we need can be found in the `samples/xml-rpc-json` directory of the gSOAP package.
To build the example client application we need `stdsoap2.h`, `stdsoap2.c`, `json.h`, `json.c`, `xml-rpc.c` and the generated `soapStub.h`, `soapH.h`, and `soapC.c` files:
    [command]
    cc -DWITH_OPENSSL -DWITH_GZIP -o currentTime currentTime.c \
      xml-rpc.c json.c stdsoap2.c soapC.c -lcrypto -lssl -lz
This may look odd, to include "soap-related" files in the build steps, but this is with a reason. We can combine JSON with all of our XML/SOAP Web services by simply adding an `#import "xml-rpc.h"` to the header file for soapcpp2 to process. The `xml-rpc.h` file specifies the data model to support JSON and XML-RPC. When combining XML/SOAP with JSON, we compile the `json.c` and `xml-rpc.c` files also, as shown.
OpenSSL and Zlib are required for our client application to work propertly with HTTPS.
[ To top](#)
Implementing a CGI server application
-------------------------------------
The server application `currentTimeServer.c` implements the JSON API with CGI as follows:
    #include "json.h"
    int main()
    {
      struct soap *ctx = soap_new1(SOAP_C_UTFSTRING);
      struct value request;
        
      /* receive JSON request value */
      if (soap_begin_recv(ctx)
       || json_recv(ctx, &request)
       || soap_end_recv(ctx))
      {
        soap_send_fault(ctx); /* or better use json_send_fault(ctx) */
      }
      else
      {
        struct value *response = new_value(ctx);
      
        /* if the name matches: set response to time, else error */
        if (is_string(&request) && !strcmp(*string_of(&request), "getCurrentTime"))
        {
          *dateTime_of(response) = soap_dateTime2s(ctx, time(0));
        }
        else
        {
          *string_of(value_at(response, "fault")) = "Wrong method";
          *value_at(response, "detail") = request;
        }
        /* set the http content type */
        ctx->http_content = "application/json; charset=utf-8";
        /* send the response */
        if (soap_response(ctx, SOAP_FILE)
         || json_send(ctx, response)
         || soap_end_send(ctx))
          soap_send_fault(ctx); /* or better use json_send_fault(ctx) */
      }
      soap_destroy(ctx);
      soap_end(ctx);
      soap_free(ctx);
      return 0;
    }
    /* Don't need a namespace table. We put an empty one here to avoid link errors */
    struct Namespace namespaces[] = { {NULL, NULL} };
Install the CGI application in the cgi-bin folder of your Web server.
[ To top](#)
Implementing a stand-alone multi-threaded server application
------------------------------------------------------------
This example shows a stand-alone iterative server that accepts incoming requests on a host port. The program is the same as the CGI service except for the service request dispatching over sockets in a loop:
    #include "json.h"
    #include "plugin/threads.h"
    int serve_request(struct soap*);
    int main(int argc, char **argv)
    {
      struct soap *ctx = soap_new1(SOAP_C_UTFSTRING);
      int port = 8080;
      if (!soap_valid_socket(soap_bind(ctx, NULL, port, 100)))
      {
        soap_print_fault(ctx, stderr);
        exit(1);
      }
      soap_set_mode(ctx, SOAP_IO_KEEPALIVE); /* enable HTTP keep-alive, which is optional */
      ctx->send_timeout = 10;
      ctx->recv_timeout = 10;
      ctx->transfer_timeout = 30;
      while (1)
      {
        if (!soap_valid_socket(soap_accept(ctx)))
        {
          soap_print_fault(ctx, stderr);
        }
        else
        {
          THREAD_TYPE tid;
          void *arg = (void*)soap_copy(ctx);
          /* use updated THREAD_CREATE from plugin/threads.h https://www.genivia.com/files/threads.zip */
          if (!arg)
            soap_closesock(ctx);
          else
            while (THREAD_CREATE(&tid, (void*(*)(void*))serve_request, arg))
              sleep(1);
        }
      }
      soap_destroy(ctx);
      soap_end(ctx);
      soap_free(ctx);
      return 0;
    }
    int serve_request(struct soap* ctx)
    {
      /* HTTP keep-alive max number of iterations */
      unsigned int k = ctx->max_keep_alive;
      struct value *request = new_value(ctx);
      int err;
      THREAD_DETACH(THREAD_ID);
      do
      {
        if (ctx->max_keep_alive > 0 && !--k)
          ctx->keep_alive = 0;
        /* receive JSON request */
        if (soap_begin_recv(ctx)
         || json_recv(ctx, request)
         || soap_end_recv(ctx))
        {
          soap_send_fault(ctx); /* or better use json_send_fault(ctx) */
        }
        else
        {
          struct value *response = new_value(ctx);
      
          if (is_string(request) && !strcmp(*string_of(request), "getCurrentTime"))
          {
            *dateTime_of(response) = soap_dateTime2s(ctx, time(0));
          }
          else
          {
            *string_of(value_at(response, "fault")) = "Wrong method";
            *value_at(response, "detail") = *request;
          }
          ctx->http_content = "application/json; charset=utf-8";
          if (soap_response(ctx, SOAP_FILE)
           || json_send(ctx, response)
           || soap_end_send(ctx))
            soap_send_fault(ctx); /* or better use json_send_fault(ctx) */
        }
        /* close (keep-alive may keep socket open when client supports it) */
        soap_closesock(ctx);
      } while (ctx->keep_alive);
      err = ctx->error;
      /* clean up */
      soap_destroy(ctx);
      soap_end(ctx);
      soap_free(ctx);
      return err;
    }
    /* Don't need a namespace table. We put an empty one here to avoid link errors */
    struct Namespace namespaces[] = { {NULL, NULL} };
HTTP Keep Alive is enabled by adding the `SOAP_IO_KEEPALIVE` to `soap_new1()` or with `soap_set_mode(ctx, SOAP_IO_KEEPALIVE)`.  This enables the inner loop to handle multiple requests over the current connection.  Make the JSON response indented with the `SOAP_XML_INDENT` flag.
To combine JSON REST with SOAP/XML services that are based on `soap_serve()` to serve SOAP/XML requests, see the [XML-RPC & JSON/JSONPath](https://www.genivia.com/doc/xml-rpc-json/html/index.html#soap) documentation.
See the [tutorials](https://www.genivia.com/tutorials.html) on how to use HTTPS and how to harden stand-alone services.
See the [documentation](https://www.genivia.com/docs.html) on how to use ISAPI and Apache modules to develop services.
[ To top](#)
Build steps for the server application
--------------------------------------
Similar to the client example above, the use of JSON requires a one-time step to generate a data model that supports both JSON and the older XML-RPC protocols:
    [command]
    soapcpp2 -c -CSL xml-rpc.h
The `xml-rpc.h` file and all other source code files that we need can be found in the `samples/xml-rpc-json` directory of the gSOAP package.
To build the example server application we need `stdsoap2.h`, `stdsoap2.c`, `json.h`, `json.c`, `xml-rpc.c` and the generated `soapStub.h`, `soapH.h`, and `soapC.c` files:
    [command]
    cc -DWITH_OPENSSL -DWITH_GZIP -o currentTimeServer currentTimeServer.c \
      xml-rpc.c json.c stdsoap2.c soapC.c -lcrypto -lssl -lz
OpenSSL and Zlib are required for our server application to work propertly with HTTPS.
[ To top](#)
Running the example
-------------------
    [command]
    ./currentTimeServer 8080 &
    ./currentTime
    Time = 2017-06-05T17:26:12Z
[ To top](#)