Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write documentation on using the smithy4s json module directly #1653

Open
wants to merge 4 commits into
base: series/0.18
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions modules/docs/markdown/06-guides/using-json-module.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Using Smithy4s Json Module

Smithy4s includes functionality to encode and decode Json with the Scala types it generates. This is used automatically by Smithy4s for powering server and client implementations for the `alloy#simpleRestJson` protocol. In some cases the use of the standalone Json encoder/decoder is
desired, like for serializing an object to Json before saving it to an object store. For
these cases, the json module from Smithy4s can be used.

### Smithy Spec

In this guide we will be using the following smithy specification

```smithy
namespace example

structure Person {
@required
name: String,
age: Integer,
email: String,
address: Address
}

structure Address {
street: String,
city: String,
country: String,
zipCode: Integer
}
```

## Reading and Writing Json

Smithy4s creates a `Schema` for each smithy data type. The json module provides interpreters such that from a `Schema` we can get a Json codec. To use
it just call the read and write methods on the `Json` object.

> Note: If the `Schema` is non-static, such as a dynamically generated one, then reading and writing Json may result in memory leaks.

```scala
import example.{Person, Address}
import smithy4s.Blob
import smithy4s.json.Json

val bob = Person("Bob", Some(20), Some("bob@example.com"), None)

val bobBlob = Json.writeBlob(bob)
val bobString = Json.writePrettyString(bob)
val bob2 = Json.read[Person](bobBlob)

println(bobBlob) // outputs: ArraySliceBlob(..., 0, 49)
println(bobString) // outputs:
// {
// "name": "Bob",
// "age": 20,
// "email": "bob@example.com"
// }
```

## Serializing other data types

If you have data types not defined in the smithy specification, but still want to use the Smithy4s Json module on these data types then a `Schema` will have to be created for the data types.
More information around creating schemas can be found in the [Datatypes and schemas design guide](05-design/02-schemas.md). If the datatype is large and complex enough, then
defining the schema for that type could become tedious, especially if any changes to that type need to be made. In this instance it's better to just add the datatype to the smithy specification and let
smithy4s generate the code for you.

## Customizing Json Codec

If you want to control some of the options of how the Json codec works, then you will have to create your own methods that configures the `Json.payloadCodecs`.
Here's an example of configuring the Json encoder to write out `null` if any field is `None`.

```scala
import smithy4s.schema.Schema
import smithy4s.json.Json

def writeWithNulls[A: Schema](a: A): String =
Json.payloadCodecs
.configureJsoniterCodecCompiler(
_.withExplicitDefaultsEncoding(true)
)
.encoders
.fromSchema(implicitly[Schema[A]])
.encode(a)
.toUTF8String

val bobString2 = writeWithNulls(bob)

println(bobString2) // outputs: {"name":"Bob","age":20,"email":"bob@example.com","address":null}
```

`Json.payloadCodecs` exposes other methods to further control how the codec works.
Loading