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

647 views Asked by At

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:

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?

1

There are 1 answers

0
Михаил Нафталь On

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) }