The Rust JSON builder via jolt-diplomat
Why this exists
Jolt itself has no JSON library. lambda-mvp-jlt's own handler works around that by hand-interpolating a JSON string, which is fine for a handful of fixed fields and unsafe the moment a value can contain a quote or backslash. This fork answers a different question: can a real, general-purpose JSON builder be embedded into a Jolt-run Lambda via a Rust crate over FFI, built reproducibly in a container, and deployed to real Lambda infrastructure? Yes, verified end to end including a real aws lambda invoke round trip.
What's actually running
jolt-diplomat generates Jolt FFI bindings from a Rust crate's public API via Diplomat. Its examples/json crate (json_capi) wraps serde_json::Value behind a C ABI: constructors (new_object/new_array/new_string/new_number/new_bool), mutators (set_string/set_number/set_bool/set_value/push), and readers (parse/object_get/array_get/to_string) already existed upstream for reading JSON; this project's contribution to jolt-diplomat was the builder half, so a handler can actually construct a response object instead of only reading one.
src/net/b12n/lambda_mvp/json_bridge.clj loads the compiled crate (libjson_capi.so + a small generated shim) and requires diplomat.json-value, jolt-diplomat's generated Clojure wrapper around those FFI calls. json/build-response is the actual entry point:
(dr/with-opaque [resp (jv/new-object)]
(doseq [[k v] fields]
(cond
(string? v) (jv/set-string resp (name k) v)
(float? v) (jv/set-number resp (name k) (double v))
(integer? v) (jv/set-number resp (name k) (double v))
(boolean? v) (jv/set-bool resp (name k) (if v 1 0))
:else (throw (ex-info "unsupported field value type" {:key k :value v}))))
(if (seq event-json)
(dr/with-opaque [event (jv/parse event-json)]
(jv/set-value resp "event" event)
(String. (jv/to-string resp)))
(do (jv/set-bool resp "event_present" 0)
(String. (jv/to-string resp)))))
handler.clj calls this with the demo's fixed fields (greeting, runtime string, request id, warm-invocation counter) plus the raw incoming event. The incoming event is parsed, not spliced in as a string, so a malformed event is a real, typed error here instead of being silently forwarded to the caller, which is something the previous hand-interpolated approach in lambda-mvp-jlt could not detect.
Vendoring, not a git dependency
jolt-diplomat's builder API started as local, uncommitted work on top of its upstream repo, so this project vendors a snapshot rather than pinning a :git/url in deps.edn:
bb vendorcopies a lean subset of a jolt-diplomat checkout (backend/,runtime/,examples/json/json_capi/,bind.clj) intovendor/jolt-diplomat/.bb sync-bindings(local dev) runsbind.cljagainst that vendored copy, producing macOS.dylibs and the generated Clojure undersrc/diplomat/โ gitignored, regenerated on demand โ sojolt probeand a REPL work without Docker.- The
Dockerfile's build stage runs the samebind.cljinside the AL2023 container, producing Linux.soartifacts. No cross-compilation, no prebuilt binaries checked in.
Once jolt-diplomat's builder API lands upstream, this vendoring step goes away in favor of a normal :git/url/:git/sha pin.
See also
- Project README: the same material in the quickstart context, plus the corporate-proxy build-arg note for
cargo install diplomat-toolinside the Docker build. - Architecture: where
json_bridge.cljsits in the whole-system flow.