Skip to content
Lee Yunjin edited this page Oct 7, 2026 · 1 revision

JSON

CWIST bundles cJSON and adds:

  • a streaming JSON builder for writing responses without a DOM;
  • self-healing of malformed JSON (json_heal.h);
  • strict validation and binding into C structs (see Validation).

Include cJSON as <cjson/cJSON.h> (installed under include/cwist/vendor). cJSON's allocations are routed to cwist_alloc at process start, so free cJSON strings with cJSON_free() and trees with cJSON_Delete().

JSON builder

Header: <cwist/core/utils/json_builder.h>

cwist_json_builder *jb = cwist_json_builder_create();
cwist_json_begin_object(jb);
cwist_json_add_string(jb, "status", "ok");
cwist_json_add_int(jb, "code", 200);
cwist_json_add_bool(jb, "cached", false);
cwist_json_begin_array(jb, "tags");
cwist_json_end_array(jb);
cwist_json_add_null(jb, "next");
cwist_json_end_object(jb);

cwist_sstring_assign(res->body, cwist_json_get_raw(jb));
cwist_json_builder_destroy(jb);
/* {"status":"ok","code":200,"cached":false,"tags":[],"next":null} */
Function Description
cwist_json_builder *cwist_json_builder_create(void) / void cwist_json_builder_destroy(cwist_json_builder *b) Lifecycle.
cwist_json_begin_object(b) / cwist_json_end_object(b) { and }.
cwist_json_begin_array(b, key) / cwist_json_end_array(b) [ and ]; with a key, writes "key":[.
cwist_json_add_string(b, key, value), _add_int, _add_bool, _add_null Members.
const char *cwist_json_get_raw(cwist_json_builder *b) The text so far; owned by the builder, valid until destroy.

Self-healing JSON

Header: <cwist/core/utils/json_heal.h>

cwist_json_heal() repairs damaged JSON in up to three stages and stops at the first result whose confidence meets the threshold:

  1. L1, syntax: BOM, line comments, trailing commas, unbalanced brackets.
  2. L2, schema: renames aliased or fuzzy-matched field names to their canonical names and coerces types ("123" to 123 for an INT field).
  3. L3, callback: an optional function you supply (for example one that asks a language model) for input L1 and L2 cannot fix.
static const cwist_schema_field_t fields[] = {
    { "user_id", {"userId", "uid", NULL}, CWIST_FIELD_INT,    true  },
    { "name",    {NULL},                  CWIST_FIELD_STRING, true  },
    { "active",  {"is_active", NULL},     CWIST_FIELD_BOOL,   false },
};
static const cwist_schema_t schema = { fields, 3 };

cwist_heal_config_t cfg = { .threshold = 0.8, .schema = &schema };
cwist_heal_result_t r = cwist_json_heal("{\"userId\": \"7\", \"name\": \"Ann\",}", &cfg);
if (r.json) printf("level %d, confidence %.2f: %s (%s)\n", r.level, r.confidence, r.json, r.log);
cwist_heal_result_free(&r);
/* level 2, confidence 0.90: {"name":"Ann","user_id":7}
   ([L1] removed trailing comma(s); [L2] 'userId'->'user_id'; [L2] 'user_id': str->num;) */

L1 does not rewrite unquoted keys or single-quoted strings; such input needs the L3 callback.

Symbol Description
cwist_heal_result_t cwist_json_heal(const char *input, const cwist_heal_config_t *cfg) Heal; cfg may be NULL (threshold 0.8, no schema). Valid input comes back unchanged (healed = false), with L2 alignment applied when a schema is given.
int cwist_json_schema_align(cJSON *obj, const cwist_schema_t *schema, char *log, size_t log_sz) Apply L2 to a parsed object in place; returns the number of fields changed or -1.
void cwist_heal_result_free(cwist_heal_result_t *r) Free r->json.
cwist_sllm_heal_fn L3 callback type. It must return a string allocated with plain malloc, because the framework releases it with free().

cwist_heal_result_t reports json, healed, level (0 to 3), confidence and a human-readable log.

cwist_db_insert_healed() combines healing, strict validation and an INSERT; see Database.

Clone this wiki locally