Skip to content

wit/bindgen: support JSON encoding of WIT types #239

@lxfontes

Description

@lxfontes

This started in #225

Goal: JSON Serialize / Deserialize WIT Records based on WIT field names.

Progress

Approach

Centralize JSON serialization in the cm package, keeping codegen changes to a minimum.

Given a complex record type:

  record response {
      headers: list<tuple<string, list<string>>>,
      http-code: u16,
      body: response-body
  }
  variant response-body {
    ok(list<list-element>),
    err(function-error),
    platform-err(platform-error)
  }
  record list-element {
      optional-int: option<u64>,
      optional-bool: option<bool>,
  }
  record function-error {
      error: string
  }
  record platform-error {
    code: string,
    message: string
  }

and filling it up:

	hdrVals := cm.ToList([]string{"value1", "value2"})
	hdrTuple := cm.Tuple[string, cm.List[string]]{
		F0: "header-name",
		F1: hdrVals,
	}
	headers := cm.ToList([]cm.Tuple[string, cm.List[string]]{hdrTuple})
	v := somefunctioninterface.Response{
		Headers:  headers,
		HTTPCode: 200,
		Body:     somefunctioninterface.ResponseBodyErr(somefunctioninterface.FunctionError{Error: "failed"}),
	}

We should serialize it to JSON as:

{"headers":[["header-name",["value1","value2"]]],"http-code":200,"body":{"err":{"error":"failed"}}}

For comparison, this is what is produced today:

{"Headers":{},"Body":{"RequiredParam":"required","OptionalParam":{}}}

Type encoding

Whenever possible, reuse standard mappings. string -> string, u32 -> uint32, etc.

Tuple handling

Tuples are encoded as json arrays with explicit nulls.

Tuple[string,int] -> [ "some string", 42 ]
Tuple3[string, *string, int] -> [ "some string", null, 42 ]

Variant handling

Variants are encoded as json dictionaries, so they can carry the variant data.

 record somerecord {
   myvariant: somevar,
 }
  variant somevar {
    ok,
    err(string),
  }

// JSON
{ "myvariant": { "ok": true }}
{ "myvariant": { "error": "error value" }}

Option handling

Options rely on explicit null for the "None" case.

{ "myoptional": null } // cm.None
{ "myoptional": "this" } // cm.Option[string]

Questions

Zero Value Variants

Today they end up with tag = 0, this impacts de-serialization of variants. We need the ability to distinct between:

  • var v Variant
  • v := NewVariantWithZeroTagValue()
  • v := Some(NewVariantWithZeroTagValue)

atm only the Some() path de-serializes correctly ( pointers ).

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request
No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions