GitHub JSON API example
=======================
Overview
--------
This example implements a GitHub JSON API client 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 [`git.c`](git.c) is run at the command line and takes the URL of a repo and optional username and password as the command-line arguments to display the GitHub repo in JSON:
#include "json.h"
int main(int argc, char **argv)
{
if (argc < 2)
{
fprintf(stderr, "Usage: git URL [username password]\nFor example: git https://api.github.com/orgs/Genivia/repos\n\n");
exit(0);
}
else
{
struct soap *ctx = soap_new1(SOAP_C_UTFSTRING | SOAP_XML_INDENT);
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 */
if (argc > 3)
{
/* Basic authentication with username password */
if (strncmp(argv[1], "https", 5))
{
fprintf(stderr, "Basic authentication over http is not secure: use https\n");
exit(1);
}
ctx->userid = argv[2];
ctx->passwd = argv[3];
}
if (json_call(ctx, argv[1], NULL, &response))
soap_print_fault(ctx, stderr);
else
json_write(ctx, &response);
printf("\n\nOK\n");
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 C++ implementation [`git.cpp`](git.cpp) is very similar. However, in general, working with JSON data in C++ is a lot easier.
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 GitHub API is called with `json_call(ctx, "URL", NULL, &response)` using an HTTP GET because the input parameter is NULL. The response JSON value is displayed with `json_write(ctx, &response)`.
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.
See the [JSON documentation](../../doc/xml-rpc-json/html/index.html) for more details on the JSON functions to create, inspect, and retrieve values.
Authentication credentials are set with the context `ctx->userid` and `ctx->password` strings. 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 git git.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](#)
Running the example
-------------------
[command]
./git https://api.github.com/orgs/Genivia/repos
This displays the Genivia public repos.
[ To top](#)