October 2, 2025

Scala – Build Json Encoder With Circe

In the preceding tutorial, we explained how Json Decoding with Circe works in Scala. We also learnt how to create and manipulated Json values including nested fields. In this tutorial, we would then build the actual encoders.

  1. Create the Types and Instances
  2. Build Your Encoders
  3. Using Your Encoders
  4. Bonus Encoders!

 

1. Create the Types and Instances

We would be bulding encoders for two custom data types: Article and Author.

The Author data type is given below

//The Author data type
case class Author(
                   name: String, 
                   bio: Option[String]
                 )

 

The Article data type is give below:

//The Article data type
case class Article(
                    id: UUID,
                    title: String,
                    content: String,
                    author: Author
                  )

Note from the above type definition that the Author type is part of the Article type.

These classes by the way are case classes. These classes provide the apply method which takes care of object construction. So you don’t have to use the new keyword for creating new objects. They are normally used to model immutable types. More on case classes here.

Let’s now create a few instances of Author and Article that would use to test the encoder that we will build.

//Create two Article instances
val article1: Article = Article (
    UUID.randomUUID(),
    "All That Glitters is Not Gold",
    "Take it or Leave it",
    author1    
)

val article2: Article = Article (
    UUID.randomUUID(),
    "You Dance to Purple Rain",
    "Like We Used To",
    author2
)    

 

2. Build the Encoders

Now we would go ahead to build the encoder that could convert from an instance of Author to Json values. Same for Article as well.

// An Encoder to encoder an an Author type into Json Value
implicit val authorEncoder: Encoder[Author] = author => Json.obj(
    "name" -> author.name.asJson,
    "bio" -> author.bio.asJson
)

 

The encoder for Article type is shown below, I call it articleEncoder

//An Encoder to encoder an article type into Json value
implicit val articleEncoder: Encoder[Article] = article => Json.obj(
    "id" -> article.id.asJson,
    "title" -> article.title.asJson,
    "content" -> article.content.asJson,
    "author" -> article.author.asJson
)

 

3. Using your Encoder

How then do you use your encoder to encoder instances?

To use the encoder to encode an instance, you simply call the asJson function on the instance. The code below encodes the instances of author1 and article1 into Json values and prints them out to the console

//Perform Encoding using your encoder
println(article1.asJson)
    
println(author1.asJson)

 

4. Bonus Encoders!

Once you write an encoder for a given type T, then circe will give you the following encoders for T. Therefore, the Encoder[Author], we would have the following encoders for free:

  • Encoder[Option[Author]]
  • Encoder[List[Author]]
  • Encoder[Array[Author]]
  • Encoder[Set[Author]]
  • Encoder[Map[Author]]
  • Encoder[Vector[Author]]
  • Encoder[NonEmptyList[Author]]

The code below creates a list of authors and uses the free Encoder[List[Author]] to encodes the list of authors and print them out

//Using the free encoders
val authorList = List(author1, author2)
println(authorList.asJson.spaces2)

 

Well, so far so good! Now we would talk about Decoders in the next tutorial.

Leave a Reply