How can I customize jsonapi-rails response? - json

Given a class User, I want to create a response with keys which value is a serialized User. For example:
{
key1: user_list_1,
key2: user_list_2,
key3: user_list_3,
}
I already have a app/serializers/serializable_user.rb file. If I wanted only only list, would be like render jsonapi: user_list. How would this work with a custom response?
I could not find on documentation: http://jsonapi-rb.org/

Just found out after cloning the repo. You can create an instance of Renderer and call "render":
renderer = JSONAPI::Serializable::Renderer.new
{
key1: renderer.render(user_list_1, class: SerializableUser),
key2: renderer.render(user_list_2, class: SerializableUser),
key3: renderer.render(user_list_3, class: SerializableUser)
}

Related

It is really tedious to write a bunch of data classes for parsing a simple JSON using Kotlin's seriallization library. Any better way?

I tried parsing JSON using Kotlin's default serialization library. However, I found it really overwhelming to write a bunch of data classes to deserialize a simple JSON string.
To illustrate,
{
"artists": {
"items": [
{
"genres": [
"desi pop",
"filmi",
"modern bollywood"
],
"images": [
{
"url": "https://i.scdn.co/image/ab6761610000e5ebb2b70762d89a9d76c772b3b6"
}
],
"name": "Arijit Singh",
"type": "artist"
}
]
}
}
for this data, I had to write these many classes,
#Serializable
data class Root(val artists: SubRoot)
#Serializable
data class SubRoot(val items: List<Artist>)
#Serializable
data class Artist(
val genres: List<String>,
val images: List<Image>,
val name: String,
val type: String
)
#Serializable
data class Image(val url: String)
Does anybody know a better way? Some library with in-built magic that does these kind of stuff for me?
If you don't want to use the automatic mapping you can just parse them as JsonElements and do your own thing instead of letting the library map them to those data classes.
https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#json-elements
For example, if you want to get that url, you could do:
val root = Json.parseToJsonElement(json)
return root.
jsonObject["artists"]?.
jsonObject?.get("items")?.
jsonArray?.get(0)?.
jsonObject?.get("images")?.
jsonArray?.get(0)?.
jsonObject?.get("url")?.
jsonPrimitive.toString()
)
This specific example will return null if any field couldn't be found while traversing the tree. It will give an IllegalArgumentException if any of the casts fail.

Ktor: How to serialize/deserialise JSON-API (vnd.api+json)

I'm looking to rewrite a spring javafx application in Kotlin using Ktor. I am new to both Spring and Ktor.
I'm having trouble using Ktor to figure out how to approach serialization and deserialisation of POJOs. (These POJOs are part of a common library).
The API I'm trying to serve requests to with Ktor uses:
Hibernate ORM as ORM mapper
Elide with RSQL filters to serve JSON-API conform data
For example "data/event" would return:
{
"data": [
{
"type": "event",
"id": "15b6c19a-6084-4e82-ada9-6c30e282191f",
"attributes": {
"imageUrl": null,
"name": "some text",
"type": "NUMERIC"
}
}, // and more event objects
]
}
Looking at the codebase in the spring application, it looks like they are using a RestTemplate to deserialise the above into an Event class (which only has an id, imageUrl, name and type as variables). Spring seems to automatically know how to get a POJO from JSON-API.
How can I do the same with Ktor? I tried the simplest:
val response = client.request<List<Event>>("data/event")
With the serialiser as gson:
install(JsonFeature) {
serializer = GsonSerializer()
}
But this results in a list of Event objects with none of their variables correctly set.
I have to make a wrapper class:
data class MyWrapper(val data: List<Event>)
And with that it will populate the list with the objects id set correctly, but none of the other attributes. So by default it looks like Ktor isnt configured for JSON-API. How can I change this?
I believe JSON:API is not supported out of the box. You need to write your own serializer, or use another wrapper class:
class JSONAPI<T>(val type: String, val id: String, val attributes: T)
data class MyWrapper(val data: List<JSONAPI<Event>>)
The problem here is that all fields in Event except of id will be filled. So you will need to adjust deserialization result:
val response: List<Event> = client.request<MyWrapper>("data/event").data.filterNotNull().map { it.attributes.copy(id = it.id) }

How to desgin a class for json when I use Gson in Kotlin?

I'm a beginner of Json and Gson, I know I can map json into a class, and map a class to json via Gson.
"My Json" is a json data, I try to design a class "My Class" to map, but I think that "My Class" is not good. Could you show me some sample code? Thanks!
My Class
data class Setting (
val _id: Long,
val Bluetooth_Stauts: Boolean,
val WiFi_Name,String
val WiFi_Statuse: Boolean
)
My Json
{
"Setting": [
{
"id": "34345",
"Bluetooth": { "Status": "ON" },
"WiFi": { "Name": "MyConnect", "Status": "OFF" }
}
,
{
"id": "16454",
"Bluetooth": { "Status": "OFF" }
}
]
}
Updated
The following is made by Rivu Chakraborty's opinion, it can work well, but it's to complex, is there a simple way?
data class BluetoothDef(val Status:Boolean=false)
data class WiFiDef(val Name:String, val Status:Boolean=false)
data class MDetail (
val _id: Long,
val bluetooth: BluetoothDef,
val wiFi:WiFiDef
)
data class MDetailsList(val mListMetail: MutableList<MDetail>)
var mBluetoothDef1=BluetoothDef()
var mWiFiDef1=WiFiDef("MyConnect 1",true)
var aMDetail1= MDetail(5L,mBluetoothDef1,mWiFiDef1)
var mBluetoothDef2=BluetoothDef(true)
var mWiFiDef2=WiFiDef("MyConnect 2")
var aMDetail2= MDetail(6L,mBluetoothDef2,mWiFiDef2)
val mListMetail:MutableList<MDetail> = mutableListOf(aMDetail1,aMDetail2)
var aMDetailsList=MDetailsList(mListMetail)
val json = Gson().toJson(aMDetailsList)
As per your JSON Structure, I think below class definition should work with Gson
data class Setting (
val id: Long,
val Bluetooth: BluetoothDef,
val WiFi:WiFiDef
)
data class BluetoothDef(val Status:String)
data class WiFiDef(val Name:String, val Status:String)
Explanation -
If you're getting an object in your JSON, you should define a class for that to use with Gson.
Data types should match, use String if you're getting Strings like "ON" and "OFF". You can use Boolean if you're getting true and false (without quotes).
The JSON Element name should match the variable/property name unless you're using #SerializedName to define JSON variable name while using different variable/property name.
*Note You can rename the classes if you want
I think it'll be helpful for you

How to Parse this JSON with LibGDX

"components":[
{
"class":"AssetReference",
"asset":{
"class":"TextureRegionAsset",
"relativePath":"gfx/opengraph.png"
}
},
{
"class":"Layer"
},
{
"class":"ProtoVisSprite",
"width":5,
"height":5
},
{
"class":"Transform",
"x":0.13817275,
"y":2.8430145,
"scaleX":0.2,
"scaleY":0.2
},
{
"class":"Origin"
},
{
"class":"Tint"
},
{
"class":"Renderable",
"zIndex":2
},
{
"class":"VisID",
"id":"scratch"
}
]
Im having some issues in parsing the nested asset with LibGDX. Does anyone know how to assign asset to AssetReference with the relativePath from TextureRegionAsset?
I know I could strip out the "class" handling and simple parse the JSON but I need to be able to handle this with LibGDX.
Ideally Im looking to parse the data and create a sprite from the JSON.
Thanks.
You can use JsonReader and get JsonValue for that.
JsonReader json = new JsonReader();
JsonValue base = json.parse(Gdx.files.internal("file.json"));
//print json to console
System.out.println(base);
//get the component values
JsonValue component = base.get("components");
//print class value to console
System.out.println(component.getString("class"));
//array objects in json if you would have more components
for (JsonValue component : base.get("components"))
{
System.out.println(component.getString("class"));
System.out.println(component.get("asset").getString("class");
System.out.println(component.get("asset").getString("relativePath");
}
There is actually a useful libgdx wiki page for this:
https://libgdx.com/wiki/utils/reading-and-writing-json
Apparently it seems to work fine with nested classes on its own already.
The wiki page has this example:
Json json = new Json();
Person person = json.fromJson(Person.class, text);
Using the following as text:
{
class: com.example.Person,
numbers: [
{
class: com.example.PhoneNumber,
number: "206-555-1234",
name: Home
},
{
class: com.example.PhoneNumber,
number: "425-555-4321",
name: Work
}
],
name: Nate,
age: 31
}
This is using an example class "Person" with the following properties:
ArrayList numbers
String name
int age
The String text is the result of json.toJson(person). Your resulting serialized string seems the same format, which makes me assume you're already using the Json serializer, but not the unserializer.

Converting json String into different objects at runtime based on their content

I'm invoking a web service that returns JSON.
The service returns either one of the following response.
case 1:
JSON:
[ {"name":"somevalue1", "key1":"value1", "key2":"value2"},
{"name":"somevalue1", "key1":"value1", "key2":"value2"},
{"name":"somevalue1", "key1":"value1", "key2":"value2"} ]
case class:
case class ValidResponse(name: String, key1: String, key2: String)
case 2:
JSON:
{"name": "invalid-response"}
Case class:
case class InvalidResponse(name:String)
I'm using json4s to parse the response as follows:
val parsedRes = parse(responseJson)
val objs: List[ValidResponse] = j.extract[List[ValidResponse]]
This works if the response string is the json in case 1. However, I get a parsedException in case the response string contains the json in case 2.
How can I handle response of multiple types?
A better way is to use one common class for both types of responses (valid and invalid):
case class Response(name: String, key1: Option[String], key2: Option[String]).
Play Framework has a great JSON parser. You can utilize this. Note that your Scala project does not have to be a Play project. You just need to import the library.
https://www.playframework.com/documentation/2.4.x/ScalaJson