Blog post
A JSON API implementation written in Kotlin, supporting your favorite JSON parsers!
What is Izzy?
Izzy is a 🐶. Also, Izzy is a JSON API standard implementation in Kotlin. It’s a library that allows you to plug in your JSON parser of choice, say which types are JSON-API types and it will automagically serialise and deserialise your objects for you from and to JSON API compliant forms. We’ve built it to work together with your favourite JSON parsers, be it Gson, Jackson, or Moshi (in progress) whatever you choose - instead of forcing a parser on you.
How to set it up:
1. Add JitPack or MavenCentral repository to root project build.gradle
file:
allprojects { r
epositories {
...
mavenCentral()
maven { url 'https://jitpack.io' } } }
2. Add a JSON-Parser dependency to app/module level build.gradle
Jackson:
implementation 'com.undabot.izzy-json-api-android:jackson-adapter:<version>'
Gson
implementation 'com.undabot.izzy-json-api-android:gson-adapter:<version>'
3. Register the types you want or need.
- When you are setting up your instance of
Izzy
, you need to pass theIzzyConfiguration
a list of classes (or just one) you're going to use with Izzy. - For example, when using
Izzy
with Jackson, you'd create an instance like this:
Izzy(
JacksonParser(
IzzyConfiguration(
ArticleResource::class.java,
PersonResource::class.java
)
)
)
4. Let your models extend IzzyResource
and annotate them using @Type(“yourTypeHere”)
- relationships must be annotated with
@Relationship(“nameGoesHere”)
@Type("articles")
data class ArticleResource(
var title: String? = null,
var body: String? = null,
var created: String? = null,
var updated: String? = null
): IzzyResource {
@Relationship("coauthors") var coauthors: List<PersonResource>? = emptyArray()
@Relationship("author") var authors: PersonResource? = null
}
5. Add a Retrofit plugin if you use Retrofit (or don’t if you don’t)
implementation 'com.undabot.izzy-json-api-android:retrofit-converter:<version>'
And you’re ready to be JSON-API Compliant!
Components:
IzzyResource
- the base resource class
- ensures your objects has an
ID
, - contains
meta
andlinks
by default if available - all your resources must extend
IzzyResource
JsonDocument
- a wrapper class containing your top-level members:
links
,meta
, anddata
orerror
- all
Izzy
deserialization methods return aJsonDocument
from which you can extract the data
Izzy
- instance of your deserializer to which you pass your Json Parser with Izzy Configuration
IzzyConfiguration
- configuration of the Izzy Parser. Holds the Classes you'll use with the
Izzy
(classes annotated with@Type
)
JsonParser
- an interface that wraps popular JSON Parsing libraries - For now, you have modules you can include if you use Jackson and Gson in your project (Moshi on the way...)
Custom JsonParser
To implement your own JsonParser
, just implement the IzzyJsonParser
and JsonElements
interfaces and you can use your preferred parser
Make sure to add test for it - you can extend existing test classes which will ensure that implementation is valid. (JsonElementsShould
& IzzyJsonParserShould
)
Annotations:
@Type(val typeName: String)
- annotation that associates this class with it’s JSON API type.
- the argument is the JSON API Type of this object.
@Relationship(val name: String)
- annotation that associates the field with a JSON API relationship.
- Izzy's relationships can be set on both single and Collection based objects.
@Nullable
- used when field should be serialized to
null
fornull
value - if not added to field,
null
values will be omitted from json
Under the hood
Under the hood, Izzy uses reflection to find your relationships, deserialize them and bind them to the resource.
! Limitations !
Deserialization
- relationship
links
are not yet supported
Serialization
- custom attributes naming is not used when attributes are serialized
- parser is currently using field name directly and not property from
@SerializedName
or@JsonProperty
- e.g.
@SerializedName("custom_name") var name: String
will be serialized toname
- parser is currently using field name directly and not property from
links
serialization is not supported currently on any levelmeta
serialization is not supported currently on any level
Example - using Jackson and Retrofit
Define resource models
import com.fasterxml.jackson.annotation.JsonProperty
import com.undabot.izzy.annotations.Nullable
import com.undabot.izzy.annotations.Relationship
import com.undabot.izzy.annotations.Type
import com.undabot.izzy.models.IzzyResource
@Type("articles")
data class ArticleResource(
// Default values are set because an empty constructor is required
@JsonProperty("title") var title: String? = null,
// Field will be serialized to `null` if value is `null` at `@Nullable` annotated field
@Nullable @JsonProperty("description") var description: String? = null,
@JsonProperty("keywords") var keywords: ArrayList<String>? = null,
// non-resource object within attributes
@JsonProperty("custom_object") var customObject: CustomObject? = null
): IzzyResource() {
@Relationship("coauthors") var coauthors: List<Person>? = null
@Relationship("author") var author: Person? = null
}
@Type("persons")
data class PersonResource(
@JsonProperty("name") var name: String? = null
): IzzyResource() {
@Relationship("favorite_article") var favoriteArticle: ArticleResource? = null
}
Initialize Izzy parser
// Register all resources in Izzy Configuration
val izzyConfiguration = IzzyConfiguration(
arrayOf(
ArtistResource::class.java,
PersonResource::class.java
)
)
val parser = JacksonParser(izzyConfiguration) // or GsonParser when Gson is used
// Initialize Izzy with parser
val izzy = Izzy(parser)
Initialize IzzyRetrofitConverter
val izzyRetrofitConverter = IzzyRetrofitConverter(izzy)
Add as Converter factory to Retrofit
and create your api service
val retrofit = Retrofit.Builder()
.baseUrl("https://undabot.com")
.client(okHttpClient)
.addConverterFactory(izzyRetrofitConverter)
.build
val apiService = retrofit.create(ApiService::class.java)
Api service example
interface ApiService {
@GET("articles")
fun articles(): Response<JsonDocument<List<ArticleResource>>>
@GET("article/{id}")
fun article(@Path("id") id: String): Response<JsonDocument<ArticleResource>>
@GET("person/{id}")
fun person(@Path("id") id: String): Response<JsonDocument<PersonResource>>
@POST("article")
fun createArticle(
@Body articleBody: ArticleResource
): Response<JsonDocument<ArticleResource>>
}
Contributing
Please take the time to carefully read the following guide. These rules help make the best out of your time, the code reviewer's time and the general consistency of the project.
General rules
All contributions are handled via Pull Requests (PRs). Your PR must target the develop branch. Your PR is required to pass all tests and contain clear description. By making contributions to this project you give permission for your code to be used under the same license.
Reporting Issues
A great way to contribute to the project is to send a detailed issue when you encounter a problem. We always appreciate a well-written, thorough bug report. Before creating new issue make sure to go through issue list and look for potential duplicate of your issue. If you find a match in issues list please leave a vote or additional comment to help us prioritize most common issues.
Be sure to include in your issue:
- Descriptive title - use keywords so others can find your bug (avoiding duplicates)
- Steps to trigger the problem that are specific, and repeatable
- What happens when you follow the steps, and what you expected to happen instead. Include the exact text of any error messages if applicable.
- Version of json-api-android used
- Did this work in a previous version? If so, also provide the version that it worked in.
- Device type & OS version where this issue can be reproduced.