1# JSON serialization of `cty` values 2 3[The `json` package](https://godoc.org/github.com/zclconf/go-cty/cty/json) 4allows `cty` values to be serialized as JSON and decoded back into `cty` values. 5 6Since the `cty` type system is a superset of the JSON type system, two modes 7of operation are possible: 8 9The recommended approach is to define the intended `cty` data structure as 10a `cty.Type` -- possibly involving `cty.DynamicPseudoType` placeholders -- 11which then allows full recovery of the original values with correct type 12information, assuming that the same type description can be provided at 13decoding time. 14 15Alternatively, this package can decode an arbitrary JSON data structure into 16the corresponding `cty` types, which means that it is possible to serialize 17a `cty` value without type information and then decode into a value that 18contains the same data but possibly uses different types to represent 19that data. This allows direct integration with the standard library 20`encoding/json` package, at the expense of type-lossy deserialization. 21 22## Type-preserving JSON Serialization 23 24The `Marshal` and `Unmarshal` functions together provide for type-preserving 25serialization and deserialization (respectively) of `cty` values. 26 27The pattern for using these functions is to define the intended `cty` type 28as a `cty.Type` instance and then pass an identical type as the second argument 29to both `Marshal` and `Unmarshal`. Assuming an identical type is used for both 30functions, it is guaranteed that values will round-trip through JSON 31serialization to produce a value of the same type. 32 33The `cty.Type` passed to `Unmarshal` is used as a hint to resolve ambiguities 34in the mapping to JSON. For example, `cty` list, set and tuple types all 35lower to JSON arrays, so additional type information is needed to decide 36which type to use when unmarshaling. 37 38The `cty.Type` passed to `Marshal` serves a more subtle purpose. Any 39`cty.DynamicPseudoType` placeholders in the type will cause extra type 40information to be saved in the JSON data structure, which is then used 41by `Unmarshal` to recover the original type. 42 43Type-preserving JSON serialization is able to serialize and deserialize 44capsule-typed values whose encapsulated Go types are JSON-serializable, except 45when those values are conformed to a `cty.DynamicPseudoType`. However, since 46capsule values compare by pointer equality, a decoded value will not be 47equal (as `cty` defines it) with the value that produced it. 48 49## Type-lossy JSON Serialization 50 51If a given application does not need to exactly preserve the type of a value, 52the `SimpleJSONValue` type provides a simpler method for JSON serialization 53that works with the `encoding/json` package in Go's standard library. 54 55`SimpleJSONValue` is a wrapper struct around `cty.Value`, which can be 56embedded into another struct used with the standard library `Marshal` and 57`Unmarshal` functions: 58 59```go 60type Example struct { 61 Name string `json:"name"` 62 Value SimpleJSONValue `json:"value"` 63} 64 65var example Example 66example.Name = "Ermintrude" 67example.Value = SimpleJSONValue{cty.NumberIntVal(43)} 68``` 69 70Since no specific `cty` type is available when unmarshalling into 71`SimpleJSONValue`, a straightforward mapping is used: 72 73* JSON strings become `cty.String` values. 74* JSON numbers become `cty.Number` values. 75* JSON booleans become `cty.Bool` values. 76* JSON arrays become `cty.Tuple`-typed values whose element types are selected via this mapping. 77* JSON objects become `cty.Object`-typed values whose attribute types are selected via this mapping. 78* Any JSON `null` is mapped to `cty.NullVal(cty.DynamicPseudoType)`. 79 80The above mapping is unambiguous and lossless, so any valid JSON buffer can be 81decoded into an equally-expressive `cty` value, but the type may not exactly 82match that of the value used to produce the JSON buffer in the first place. 83