Summary#
JsonSerializer is the JSON surface, spelled exactly as in C# (System.Text.Json). It has two members:
var body = JsonSerializer.Serialize(order); // a value → a JSON string
var order = JsonSerializer.Deserialize<Order>(body); // a JSON string → a typed OrderIt is pure — no capability, no using required (though a pasted using System.Text.Json; is accepted and does
nothing). It pairs naturally with Http.*: serialize a request body, deserialize a response.
Signature#
string JsonSerializer.Serialize(value) // value = a scalar, a class, a list, or a map
T JsonSerializer.Deserialize<T>(string json) // T = a classDescription#
Serialize accepts any value and returns compact JSON (matching System.Text.Json's default): a scalar
("x", 42, true, 3.5), a class instance (→ a JSON object of its fields), a list (→ an array), a map
(→ an object). Property names are the field names as declared. byte[] becomes base64.
Deserialize<T> parses JSON into a T, where T is a class — the DTO you want the data as. It fills each
declared field from the matching JSON member, coercing by the field's type: scalars, a nested class (→ a nested
object), and a collection (→ a list of elements). A member missing from the JSON is left at its default; a JSON null
sets null. A field the class doesn't declare is ignored.
T must be a class, not an entity — an entity has identity and persistence a JSON body can't carry.
Storing it: the Json property type#
A property declared Json holds a document, and it is string-backed — so Serialize writes one and the property
reads back into Deserialize:
class Detail { public int Attempt; public string Reason; }
entity Job { [Required, MaxLength(50)] string Name; Json Detail; }
void Record() {
var j = new Job { Name = "j1", Detail = JsonSerializer.Serialize(new Detail { Attempt = 2, Reason = "retry" }) };
}
int Attempts(Job job) {
return JsonSerializer.Deserialize<Detail>(job.Detail).Attempt;
}That is the whole surface: a Json property takes a string and gives one back. It is not parsed or validated on
the way in — the same rule a Markdown property follows — so Serialize is how you sensibly produce one rather than
building the text by hand.
⚠ There is no object-literal form: Detail = new { attempt = 2 } does not compile, because an anonymous object is
not a value in Osy#. Declare the shape as a class and serialize it, which is what you would do in C# anyway and
gives the document a name the rest of your code can use.
Serializing an entity produces a shallow object: its Id and scalar properties, with an EntityRef
rendered as its FK id (not the nested entity) and collections omitted. This is deliberate — expanding relations by
default would invite reference cycles and load a record's whole object graph. When you want a specific nested shape,
map the entity into a class DTO (which serializes fully) and serialize that.
Examples#
Round-trip a DTO through JSON:
class Order {
public string Code;
public decimal Total;
public bool Paid;
}
string ToJson(Order o) {
return JsonSerializer.Serialize(o); // {"Code":"A1","Total":42.0,"Paid":true}
}
Order FromJson(string body) {
return JsonSerializer.Deserialize<Order>(body); // typed Order, fields populated
}Parse an HTTP response body (Http.*):
app Shop {
model "model/**/*.osy";
use Osyrin.Http; // `use` is a manifest declaration — Http.* needs it
}
class Weather { public decimal TempC; public string Summary; }
Weather Fetch(string city) {
var r = Http.Get("https://api.example.com/weather/" + city);
return r.IsSuccess ? JsonSerializer.Deserialize<Weather>(r.Body) : new Weather { Summary = "unknown" };
}Nested classes and lists deserialize recursively:
class Line { public string Sku; public int Qty; }
class Cart { public string Owner; public List<Line> Lines; }
Cart Parse(string body) {
return JsonSerializer.Deserialize<Cart>(body); // Lines becomes a list of typed Line objects
}See also#
- Json — the
Jsonproperty type this writes into, and when to reach for it - Http.* — the outbound HTTP surface whose bodies this serializes / parses
- constructor — the
classtypes Serialize walks and Deserialize targets