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:
Serialize : 'T -> string
serializes a value to 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:
Parse : string -> obj
uses JavaScript'sJSON.parse
to convert a string to a value (no attribute-based transformations).Stringify :obj -> string
uses JavaScript'sJSON.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:
Encode : 'T -> obj
converts a value to a JavaScript object that is not yet stringified, such thatJSON.Stringify (Json.Encode x) = Json.Serialize x
.Decode : obj -> 'T
converts a parsed JavaScript object to a value, such thatJson.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 theclient
helper) and passing it server-side values - Sitelet endpoints with a field with
[<Json>]
attribute - Returning a
Content.Json
value from a sitelet endpoint
Supported types
JSON serializers are automatically derived for the following types, where any generic parameters are also JSON-serializable types:
unit
bool
- numeric types:
byte
,sbyte
,int16
,uint16
,int
,uint32
,int64
,uint64
,single
,float
decimal
(on the client side, requires theWebSharper.MathJS
package)string
char
System.DateTime
System.DateTimeOffset
System.TimeSpan
System.Guid
System.Numerics.BigInteger
- one-dimensional arrays:
'T []
- tuples:
'T1 * 'T2 * ... * 'Tn
System.Nullable<'T>
- unions (including
option
andlist
) - records
- enums
Map<'K, 'V>
Set<'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 to your type or proxy EncodeJson: 'T -> obj
and DecodeJson: obj -> 'T
.
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
(akaint
),int64
- Unsigned integers:
uint8
(akabyte
),uint16
,uint32
,uint64
- Floats:
single
,double
(akafloat
)
- Decimals:
decimal
- Strings:
string
andchar
- 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 optimally bear the attribute NamedUnionCases
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.
Missing the attribute, the case name would be not 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. This means that 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.
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.
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.
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.
Then, it is serialized based on its fields, similarly to F# records as mentioned above.
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.
Note however that [<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.