JSON examples
Ready-to-use examples for parsing, building, and serializing JSON documents. For the full function reference, see JSON.
Parsing a string
json_parse takes a string and returns a ready-to-use document. The root token is available through json_root, and its type is checked with json_is_*:
// handlers/jsonpage.c
#include "http.h"
#include "json.h"
void parse_json(httpctx_t* ctx) {
const char* json_string =
"{\"name\":\"alex\",\"age\":30,\"active\":true,\"balance\":165.23}";
json_doc_t* doc = json_parse(json_string);
if (!doc) {
ctx->response->send_data(ctx->response, "json parse error");
return;
}
json_token_t* object = json_root(doc);
if (!json_is_object(object)) {
ctx->response->send_data(ctx->response, "root is not an object");
json_free(doc);
return;
}
json_token_t* name = json_object_get(object, "name");
if (name) {
ctx->response->send_data(ctx->response, json_string(name));
}
json_free(doc);
}Building a document from scratch
A convenient entry point is json_root_create_object (or json_root_create_array), which creates the document and assigns the root token in one call. Tokens are created without a document: json_create_string, json_create_number, json_create_bool, json_create_null, json_create_object, json_create_array:
#include "http.h"
#include "json.h"
void build_json(httpctx_t* ctx) {
json_doc_t* doc = json_root_create_object();
json_token_t* object = json_root(doc);
json_object_set(object, "name", json_create_string("alex"));
json_object_set(object, "age", json_create_number(30));
json_object_set(object, "active", json_create_bool(1));
json_object_set(object, "balance", json_create_number(165.23));
json_object_set(object, "note", json_create_null());
ctx->response->add_header(ctx->response, "Content-Type", "application/json");
ctx->response->send_data(ctx->response, json_stringify(doc));
json_free(doc);
}You can also start from an empty document and assign the root separately with json_set_root:
json_doc_t* doc = json_create_empty();
json_token_t* object = json_create_object();
json_set_root(doc, object);Nested objects and arrays
Container tokens can be freely nested. Create the values first, then pass them to json_object_set / json_array_append:
#include "http.h"
#include "json.h"
void nested_json(httpctx_t* ctx) {
json_doc_t* doc = json_root_create_object();
json_token_t* root = json_root(doc);
// Nested "address" object
json_token_t* address = json_create_object();
json_object_set(address, "city", json_create_string("Berlin"));
json_object_set(address, "zip", json_create_number(10115));
json_object_set(root, "address", address);
// "tags" array with prepend/append
json_token_t* tags = json_create_array();
json_object_set(root, "tags", tags);
json_array_append(tags, json_create_string("php"));
json_array_append(tags, json_create_string("c"));
json_array_prepend(tags, json_create_string("first"));
json_array_append_to(tags, 1, json_create_string("sql")); // insert at index
// Replace a value by index
json_token_t* second = json_array_get(tags, 1);
if (second) {
json_token_set_string(second, "rust");
}
ctx->response->add_header(ctx->response, "Content-Type", "application/json");
ctx->response->send_data(ctx->response, json_stringify(doc));
json_free(doc);
}Reading typed values
The numeric getters json_int, json_uint, json_llong, and json_double take an int* ok out-parameter — it is zero when the token is not a number. Use json_is_number (and the other json_is_* checks) to verify the type:
#include "http.h"
#include "json.h"
void read_numbers(httpctx_t* ctx) {
json_doc_t* doc = json_parse("{\"count\":42,\"price\":19.95,\"name\":\"alex\"}");
if (!doc) {
ctx->response->send_data(ctx->response, "parse error");
return;
}
json_token_t* object = json_root(doc);
char response[256];
json_token_t* count = json_object_get(object, "count");
if (count && json_is_number(count)) {
int ok = 0;
int value = json_int(count, &ok);
if (ok) {
snprintf(response, sizeof(response), "count = %d", value);
ctx->response->send_data(ctx->response, response);
}
}
json_free(doc);
}Strings and booleans are read directly — without the ok parameter: json_string(token), json_bool(token). The byte length of a string is returned by json_string_size.
Iterating an object and an array
The single json_it_t iterator works for both objects and arrays. For an object, the key is available through json_it_key and the value through json_it_value:
#include "http.h"
#include "json.h"
void iterate_json(httpctx_t* ctx) {
json_doc_t* doc = json_parse("{\"a\":1,\"b\":2,\"c\":3}");
if (!doc) {
ctx->response->send_data(ctx->response, "parse error");
return;
}
json_token_t* object = json_root(doc);
char response[512] = "";
for (json_it_t it = json_init_it(object); !json_end_it(&it); it = json_next_it(&it)) {
const char* key = (const char*)json_it_key(&it);
json_token_t* value = json_it_value(&it);
int ok = 0;
int num = json_int(value, &ok);
char line[64];
snprintf(line, sizeof(line), "%s=%d | ", key, ok ? num : 0);
strncat(response, line, sizeof(response) - strlen(response) - 1);
}
ctx->response->send_data(ctx->response, response);
json_free(doc);
}When iterating an array, json_it_key returns NULL — only values are available. To remove the current element as you go, call json_it_erase.
Serializing and responding
json_stringify returns a string owned by the document and freed together with it via json_free. Setting ascii_mode = 1 encodes every non-ASCII character as \uXXXX — handy for logs and compatibility with legacy clients:
#include "http.h"
#include "json.h"
void stringify_json(httpctx_t* ctx) {
json_doc_t* doc = json_parse("[\"Hello 😅\", 42, true]");
if (!doc) {
ctx->response->send_data(ctx->response, "parse error");
return;
}
doc->ascii_mode = 1; // escape non-ASCII as \uXXXX
ctx->response->add_header(ctx->response, "Content-Type", "application/json");
ctx->response->send_data(ctx->response, json_stringify(doc));
json_free(doc);
}When the string must outlive the document, use json_stringify_detach. It returns a separate copy that you must release manually with free:
char* body = json_stringify_detach(doc);
if (body) {
ctx->response->add_header(ctx->response, "Content-Type", "application/json");
ctx->response->send_data(ctx->response, body);
free(body);
}
json_free(doc);