Circe is unable to detect a field if it includes an array

There are 2 different scenarios I'm dealing with: one where I can successfully decode a single user, and another where decoding a list of users fails:

import User._
import io.circe._
import io.circe.syntax._
import io.circe.parser.decode

class UserSuite extends munit.FunSuite:
  test("List of users can be decoded") {

    val json = """|{
                  |   "data" : [
                  |       {
                  |         "id" : "someId",
                  |         "name" : "someName",
                  |         "username" : "someusername"
                  |       },
                  |       {
                  |         "id" : "someId",
                  |         "name" : "someName",
                  |         "username" : "someusername"
                  |       }
                  |   ]
                  |}""".stripMargin    
    println(decode[List[User]](json))
  }

  test("user can be decoded") {
    val json = """|{
                  |   "data" : {
                  |         "id" : "someId",
                  |         "name" : "someName",
                  |         "username" : "someusername"
                  |       }
                  |}""".stripMargin
    println(decode[User](json))
  }

The failed attempt results in this error message:

Left(DecodingFailure(List, List(DownField(data))))

This is puzzling because both the JSON structure and decoders (defined below) are identical.

final case class User(
    id: String,
    name: String,
    username: String
)

object User:
    given Decoder[List[User]] = 
        deriveDecoder[List[User]].prepare(_.downField("data"))
    
    given Decoder[User] = 
        deriveDecoder[User].prepare(_.downField("data"))

I thought everything was set up correctly based on insights from Travis' older reply, but it seems to hit a snag.

Could this be a bug? Am I missing something?

Just for context, this is using Scala 3.2.0 and circe 0.14.1

Answer №1

The important point to note is that you will require two separate encoders for the User object - one encoder should expect a data field when decoding the second JSON, and the other should not expect a data field when deriving a decoder for a list. Otherwise, the structure of the first JSON should be as follows:

"""|{
   |   "data" : [
   |       {
   |          "data" : 
   |              {
   |                 "id" : "someId",
   |                 "name" : "someName",
   |                 "username" : "someusername"
   |              }
   |       },
   |       {
   |          "data" : 
   |              {
   |                 "id" : "someId",
   |                 "name" : "someName",
   |                 "username" : "someusername"
   |              }
   |       }
   |   ]
   |}""

It is recommended to explicitly define it now:

final case class User(
                       id: String,
                       name: String,
                       username: String
                     )

object User {
  val userDec: Decoder[User] = semiauto.deriveDecoder[User]
  val preparedUserDec: Decoder[User] = userDec.prepare(_.downField("data"))

  val userListDec: Decoder[List[User]] = {
    implicit val dec: Decoder[User] = userDec
    Decoder[List[User]].prepare(_.downField("data"))
  }
}

val json =
  """|{
     |   "data" : [
     |       {
     |         "id" : "someId",
     |         "name" : "someName",
     |         "username" : "someusername"
     |       },
     |       {
     |         "id" : "someId",
     |         "name" : "someName",
     |         "username" : "someusername"
     |       }
     |   ]
     |}""".stripMargin

decode[List[User]](json)(User.userListDec)
// Right(List(User(someId,someName,someusername), User(someId,someName,someusername)))


val json1 =
    """|{
       |   "data" : {
       |         "id" : "someId",
       |         "name" : "someName",
       |         "username" : "someusername"
       |       }
       |}""".stripMargin

decode[User](json1)(User.preparedUserDec)
// Right(User(someId,someName,someusername))

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Send the output of MPDF back to the browser by utilizing JSON in combination with ExtJS

I am currently using mpdf to generate a PDF report in my PHP code. I have successfully been able to save the PDF file and view it by using Output($pdfFilePath), but now I need to send it back to the browser using JSON without saving it on the server. To ac ...

Analyzing DynamoDB Query

I am on a mission to recursively analyze a DynamoDB request made using the dynamo.getItem method. However, it seems that I am unable to locate a similar method in the DynamoDB SDK for Node.js. You can find more information about DynamoDB SDK at http://do ...

Import the complete JSON file into a variable as an array

I am struggling with loading an external json file (locations.json) into a variable and then using the information found here: http://www.json.org/js.html Despite trying various methods, I have not been successful in populating the variable. Even after fo ...

Transforming data from AFNetworking into JSON format

Utilizing AFNetworking to fetch JSON from a URL, parsing the JSON, and trying to convert it into an NSData format to populate an array. But unfortunately, it doesn't seem to be working as expected. It used to work before, so I'm puzzled by what c ...

Understanding how to parse JSON in a Node.js environment is

I'm currently investigating why the parsed request, a JSON from a jQuery AJAX call made across domains, appears to be a bit unusual. GET /sendjsondata?callback=_testcb&{%22amount%22:1800,%22name%22:%22Vasy%20Jon%22,%22cnp%22:232323,%22coborrower% ...

To add additional nested data to a JSON object in JavaScript, you can use the push method or update

Looking to enhance the nested object data within my existing object The current structure of the JSON object array resembles this: var orderDetails = [{ "utilityType": "Electric", "firstName": "ROBERT", "lastName": "GUERRERO", "utilityList": [{ ...

JSON Date Format

I'm facing an issue where I am unable to retrieve the current date using new Date() because it is in JSON format. This particular code was written using MVC C#. The date appears as \/Date(1531364413000)\/. The dates stored in the database ...

Fetching weather data from the Darksky.com API in JSON format

My goal is to retrieve weather data in JSON format from the Darksky.com API. To do this, I first successfully obtained my latitude and longitude using the freegoip.com API. However, the Darksky API requires both longitude and latitude before it can provid ...

Python is unable to retrieve JSON data from the JSON source

Currently, I'm facing a challenge in extracting data from Verizon's buyback pricing website. While exploring the "Net" requests in my browser, I stumbled upon the source of the data. The site presents information in JSON format, but despite numer ...

Export a list from R to Julia using JSON format

Imagine you have a list in R like this: x = list(a=1:3,b=8:20) You then save this to a JSON file on disk using the following code: library(jsonlite) cat(toJSON(x),file="f.json") Now, how can you read this JSON file using the Julia JSON package? Is it p ...

New and one-of-a-kind C# 90-ball Bingo cards

I am developing a bingo card generation system that includes 6 tables. Each table contains 3 rows and 9 columns, with 5 numbers and 4 empty spots in each row. The columns are divided as follows: Column 1: 1-9, Column 2: 10-19, Column 3: 20-29, Column 4: 3 ...

Converting a SQLite database to JSON using Haskell

How can I export a SQLite database to a JSON file in Haskell? Most other questions involve parsing JSON and saving it to SQLite, but I am looking to do the opposite. Any suggestions or references would be greatly appreciated. I have developed a Haskell ap ...

'Stop' function triggered as numberOfRowsInSection produces a zero value

Here is a snippet from my code: #import <UIKit/UIKit.h> #import "ServiceConnector.h" @interface PartnerTableController : UITableViewController <ServiceConnectorDelegate> @property (nonatomic, retain) IBOutlet NSMutableArray *allPartners; - ...

result of Hive query with no data

I recently created an external Hive table using a tweets json file exported from Mongo DB. However, I have noticed that when I attempt to select more than one column from the hive table, the retrieved results are not properly formatted. Some columns appear ...

Storing information in a JSON file

Is there a way to save data in a JSON file without using a database? I want to store questions from the user interface, but I haven't learnt about databases yet. I know using a database would be more efficient. Does anyone know if it's possible ...

Struggling to parse the JSON blob that was returned when using express-handlebars in node.js? Let

I am in the process of learning node.js and following a tutorial that involves making requests to the Accuweather API and receiving JSON data. Almost there ... but struggling with displaying the data: index.js const express = require('express' ...

Deciphering a JSON array by value or key

I have a JSON array that I need to parse in order to display the available locations neatly in a list format. However, I am struggling with where to start. The data should be converted to HTML based on the selected date. In addition, a side bar needs to s ...

Strategies for accessing information in a JSON response using Scrapy

I am currently utilizing scrapy in conjunction with Python. Here is the specific URL I am working with: This is a snippet of my code: def parse(self, response): jsonresponse = json.loads(response.body_as_unicode()) print("=============== ...

Utilizing a JSON object in JSP and integrating it seamlessly with JQuery

After developing a JSP application to retrieve search results using Lucene and storing them in a Bean, I utilized JQuery Ajax for displaying the outcomes. $.ajax({ url : "search.jsp", data : "search=test", success : function(html) { (" ...

"Transmitting data via HTTP POST on an Android device

While there have been previous inquiries on this topic, many of the methods mentioned are no longer relevant. I have discovered a new solution: new Thread( new Runnable() { @Override public void run() { try { St ...