JSON API
WebSharper provides a convenient and readable JSON serialization format for F# types as well as C# classes. The structure of the JSON is inferred from the type, and can be customized using attributes. This format is usable both from the server and the client side.
Using JSON on the server
WebSharper sitelets provide facilities to both parse JSON from HTTP requests and write it to HTTP responses.
- Parsing: using the
[<Json>]attribute. - Writing: using
Content.Json.
The WebSharper.Json type provides the following static methods:
| Method | Description |
|---|---|
Serialize : 'T -> string | Serializes a value to a string. |
Deserialize : string -> 'T | Deserializes a value from a string. |
Using JSON on the client
There is a JSON module available in WebSharper.JavaScript that provides access to underlying JavaScript functionality:
| Method | Description |
|---|---|
Parse : string -> obj | Uses JavaScript's JSON.parse to convert a string to a value (no attribute-based transformations). |
Stringify : obj -> string | Uses JavaScript's JSON.stringify to convert a value to a string (no attribute-based transformations). |
Typed JSON serialization is also available on the client. The WebSharper.Json type also provides the following static methods that only work on the client:
| Method | Description |
|---|---|
Encode : 'T -> obj | Converts a value to a JavaScript object that is not yet stringified, such that JSON.Stringify (Json.Encode x) = Json.Serialize x. |
Decode : obj -> 'T | Converts a parsed JavaScript object to a value, such that Json.Decode (JSON.Parse s) = Json.Deserialize s. |
Automatic JSON use
WebSharper automatically uses JSON de/serialization for the following cases:
- Remote method calls
- Creating a
Web.Control(including using theclienthelper) and passing it server-side values - Sitelet endpoints with a field with
[<Json>]attribute - Returning a
Content.Jsonvalue from a sitelet endpoint
Supported types
JSON serializers are automatically derived for the following types, where any generic parameters are also JSON-serializable types:
unitbool- numeric types:
byte,sbyte,int16,uint16,int,uint32,int64,uint64,single,float decimal(on the client side, requires theWebSharper.MathJSpackage)stringcharSystem.DateTimeSystem.DateTimeOffsetSystem.TimeSpanSystem.GuidSystem.Numerics.BigInteger- one-dimensional arrays:
'T [] - tuples:
'T1 * 'T2 * ... * 'Tn System.Nullable<'T>- unions (including
optionandlist) - records
- enums
Map<'K, 'V>Set<'T>System.Collections.Generic.IEnumerable<'T>System.Collections.Generic.List<'T>System.Collections.Generic.Queue<'T>System.Collections.Generic.Stack<'T>System.Collections.Generic.LinkedList<'T>System.Collections.Generic.Dictionary<'K, 'V>- classes with a parameterless default constructor
- structs with a constructor that initializes all fields from parameters
For records, unions, classes and structs to be JSON-serializable, all their fields must also be JSON-serializable.
Extensibility
Adding custom support for other types is currently supported only on the client side.
Add static methods EncodeJson: 'T -> obj and DecodeJson: obj -> 'T to your type or proxy. These should convert between a JSON-compatible plain JavaScript object and your type.
Format
Base types
The following base types are handled: integers (int8, int16, int32 aka int, int64), unsigned integers (uint8 aka byte, uint16, uint32, uint64), floats (single, double aka float), decimals (decimal), strings (string and char), and booleans (bool).
Collections
Values of type list<'T>, 'T[], ResizeArray<'T>, Set<'T>, Queue<'T>, and Stack<'T> are represented as JSON arrays:
Values of type Map<string, 'T> and System.Collections.Generic.Dictionary<string, 'T> are represented as flat JSON objects:
Other Map and Dictionary values are represented as an array of key-value pairs:
Tuples
Tuples (including struct tuples) are also represented as JSON arrays:
F# Records
F# records are represented as flat JSON objects. The attribute [<Name "name">] can be used to customize the field name:
F# Unions
Union types intended for use in JSON serialization should ideally bear the NamedUnionCases attribute, for producing fully readable JSON format.
There are two ways to use it, specifying a field name to hold the union case name or signaling that the case should be inferred from the field names.
If no NamedUnionCases is present, a "$" field will be used for storing the case index.
Explicit discriminator
With [<NamedUnionCases "field">], the union value is represented as a JSON object with a field called "field", whose value is the name of the union case, and as many other fields as the union case has arguments. You can use [<Name "name">] to customize the name of a union case.
Unnamed fields receive the names Item1, Item2, etc.
Without the attribute, the case name would not be stored in a readable form:
Implicit discriminator
With an argumentless [<NamedUnionCases>], no extra field is added to determine the union case; instead, it is inferred from the names of the fields present.
Each case must have at least one mandatory field that no other case in the same type has, or a compile-time error will be thrown.
Record inside union
As a special case, if a union case has a single, unnamed argument which is a record, then the fields of this record are used as the fields of the output object.
Constant cases
Union cases annotated with the attribute [<Constant c>] are represented as the corresponding constant, which can be a string, int, float or bool.
It is recommended to only use this attribute on argument-less cases. If all cases of a union are annotated with [<Constant>], then [<NamedUnionCases>] is not necessary.
Optional fields
Fields with type option<'T> are represented as a field that may or may not be there. This is the case both for unions and records.
When parsing JSON, null is also accepted as a None value.
Classes
In order to be serializable to/from JSON on the server side, a class must be annotated with the [<System.Serializable>] attribute and must have a default constructor. On the client side, these are not checked or required.
A class is serialized based on its fields, similarly to F# records. Here is an example in C#:
Then from F#:
DateTimes
Values of type System.DateTime are encoded using an ISO 8601 round-trip format string:
The format can be customized with the attribute [<DateTimeFormat>].
This attribute can be placed either on a record field of type System.DateTime or option<System.DateTime>, or on a union case with an argument of one of these types.
[<DateTimeFormat>] is only available on the server side; this attribute is ignored by client-side serialization. Do not use it if you want to use your data type for remoting.