JSON
JSON plus Accept-based content negotiation. Foundation's Codable/JSONEncoder use runtime reflection, which is unavailable under Embedded Swift, so PlumeKit's JSON is a concrete value tree serialized and parsed by byte. It works identically on the native server and the Wasm worker.
JSONValue
let body = JSONValue.object([
("id", .int(1)),
("title", .string("Hello")),
("tags", .array([.string("a"), .string("b")])),
])
return .json(body) // Response.json serializes itJSONValue (null/bool/int/double/string/array/ordered-object) serializes byte-wise (escapes only what JSON requires; UTF-8 passes through) and parses via a recursive-descent parser. parseJSON(bytes)/parseJSON(string) returns a JSONValue?; read it with json["key"], .stringValue, .intValue, etc.
Two constraints from the Wasm build:
- No
Double(String): it linksstrtod, absent in embedded wasm; numbers - No Unicode-aware String ops: keys compare and strings build/escape by byte.
are parsed by a byte-wise float routine (adequate for JSON, not bit-exact).
Models ⇄ JSON (the ORM seam)
The @Model row codec is reused for JSON; there is no second codec:
post.jsonObject() // { "id":1, "title":"…", "published":true, … }
jsonArray(posts) // [ {...}, {...} ]
Post.fromJSON(request.json()!) // build from a client payload (by column name)jsonObject() walks schema.columns + columnValues(); fromJSON maps a JSON object back into a Row by column name (absent keys → type defaults, so a payload without id is insert-ready).
Content negotiation
func index(_ request: Request) async throws -> Response {
let posts = try await Post.all().all(in: request.bindings.database)
if request.wantsJSON { return .json(jsonArray(posts)) } // Accept: application/json
return .text(/* … */) // else HTML/text
}request.wantsJSON (an Accept check), request.hasJSONBody (Content-Type), and request.json() (parse the body). A controller serves the same resource as JSON or HTML from one action.
Notes
Request and response bodies are buffered in memory, not streamed; keep very large payloads in object storage and pass references. NaN and the infinities have no JSON representation and encode as null.