{"id":19362727,"url":"https://github.com/stantanasi/retrofit-jsonapi-converter","last_synced_at":"2026-06-19T00:31:15.778Z","repository":{"id":75840702,"uuid":"358537182","full_name":"stantanasi/retrofit-jsonapi-converter","owner":"stantanasi","description":"Retrofit JsonApi Converter is an Android library for converting JSON:API response to model and model to JSON:API format","archived":false,"fork":false,"pushed_at":"2021-12-08T14:53:21.000Z","size":227,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-24T12:50:40.240Z","etag":null,"topics":["android","android-library","converter","json-api","json-api-client","json-api-serializer","kotlin","retrofit","retrofit-jsonapi-converter","retrofit2"],"latest_commit_sha":null,"homepage":"https://jitpack.io/#stantanasi/retrofit-jsonapi-converter","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stantanasi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-16T08:56:18.000Z","updated_at":"2024-12-15T11:48:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"37b5e889-7bf0-4ecf-9ae8-2e19b4416757","html_url":"https://github.com/stantanasi/retrofit-jsonapi-converter","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/stantanasi/retrofit-jsonapi-converter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stantanasi%2Fretrofit-jsonapi-converter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stantanasi%2Fretrofit-jsonapi-converter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stantanasi%2Fretrofit-jsonapi-converter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stantanasi%2Fretrofit-jsonapi-converter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stantanasi","download_url":"https://codeload.github.com/stantanasi/retrofit-jsonapi-converter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stantanasi%2Fretrofit-jsonapi-converter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34513020,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-library","converter","json-api","json-api-client","json-api-serializer","kotlin","retrofit","retrofit-jsonapi-converter","retrofit2"],"created_at":"2024-11-10T07:30:04.943Z","updated_at":"2026-06-19T00:31:15.726Z","avatar_url":"https://github.com/stantanasi.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eRetrofit JSON:API Converter\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://jsonapi.org/images/jsonapi.png\" height=\"100px\" /\u003e\n  \u003cbr /\u003e\n  A Retrofit converter for JSON:API specification.\n  \u003cbr /\u003e\n  \u003ca href=\"https://jitpack.io/#stantanasi/retrofit-jsonapi-converter\"\u003e\n    \u003cstrong\u003eImplement library »\u003c/strong\u003e\n  \u003c/a\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n  \u003ca href=\"https://github.com/stantanasi/retrofit-jsonapi-converter/issues\"\u003eReport Bug\u003c/a\u003e\n  ·\n  \u003ca href=\"https://github.com/stantanasi/retrofit-jsonapi-converter/issues\"\u003eRequest Feature\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eTable of Contents\u003c/summary\u003e\n\n- [About the project](#about-the-project)\n  - [Built with](#built-with)\n- [Getting started](#getting-started)\n  - [Prerequisites](#prerequisites)\n  - [Setup](#setup)\n- [Usage](#usage)\n  - [JSON:API response object](#jsonapi-response-object)\n  - [Setting the models](#setting-the-models)\n    - [Dynamic updates on request body](#dynamic-updates-on-request-body)\n    - [Multi-type relationship](#multi-type-relationship)\n  - [Define the endpoints](#define-the-endpoints)\n    - [JsonApiParams](#jsonapiparams)\n    - [JsonApiResponse](#jsonapiresponse)\n  - [Make the request](#make-the-request)\n    - [Fetch a collection](#fetch-a-collection)\n    - [Fetch a resource](#fetch-a-resource)\n    - [Create a resource](#create-a-resource)\n- [Contributing](#contributing)\n- [Author](#author)\n- [License](#license)\n\u003c/details\u003e\n\n\n## About the project\n\nRetrofit JSON:API Converter is a Retrofit converter for JSON:API specification\n\nJSON:API is a specification for how a client should request that resources be fetched or modified, and how a server should respond to those requests.\n\nJSON:API is designed to minimize both the number of requests and the amount of data transmitted between clients and servers. This efficiency is achieved without compromising readability, flexibility, or discoverability.\n\nThis is not an official [Square product](https://square.github.io).\n\n### Built with\n\n- [Kotlin](https://kotlinlang.org)\n- [Retrofit](https://square.github.io/retrofit)\n- [JSON:API specification](https://jsonapi.org)\n\n\n## Getting started\n\n### Prerequisites\n\nInside your root `build.gradle`, add the JitPack maven repository to the list of repositories:\n\n```gradle\nallprojects {\n  repositories {\n    ...\n    maven { url 'https://jitpack.io' }\n  }\n}\n```\n\nInside your module `build.gradle`, implement library [latest version](https://jitpack.io/#stantanasi/retrofit-jsonapi-converter):\n\n```gradle\ndependencies {\n  ...\n  implementation 'com.github.stantanasi:retrofit-jsonapi-converter:LAST_VERSION'\n}\n```\n\n### Setup\n\nAdd the following lines when creating the retrofit instance:\n- **addCallAdapterFactory(JsonApiCallAdapterFactory.create())**\n- **addConverterFactory(JsonApiConverterFactory.create())**\n\n```kotlin\nval retrofit = Retrofit.Builder()\n  .baseUrl(\"http://example.com/\")\n  .addCallAdapterFactory(JsonApiCallAdapterFactory.create())\n  .addConverterFactory(JsonApiConverterFactory.create())\n  .build()\n```\n\n\n## Usage\n\n### JSON:API response object\n\nLet's suppose you have an API that returns the following response:\n\n```json\n{\n  \"data\": {\n    \"type\": \"articles\",\n    \"id\": \"1\",\n    \"attributes\": {\n      \"title\": \"JSON:API paints my bikeshed!\"\n    },\n    \"links\": {\n      \"self\": \"http://example.com/articles/1\"\n    },\n    \"relationships\": {\n      \"author\": {\n        \"links\": {\n          \"self\": \"http://example.com/articles/1/relationships/author\",\n          \"related\": \"http://example.com/articles/1/author\"\n        },\n        \"data\": {\n          \"type\": \"people\",\n          \"id\": \"9\"\n        }\n      },\n      \"comments\": {\n        \"links\": {\n          \"self\": \"http://example.com/articles/1/relationships/comments\",\n          \"related\": \"http://example.com/articles/1/comments\"\n        },\n        \"data\": [\n          {\n            \"type\": \"comments\",\n            \"id\": \"5\"\n          },\n          {\n            \"type\": \"comments\",\n            \"id\": \"12\"\n          }\n        ]\n      }\n    }\n  },\n  \"included\": [\n    {\n      \"type\": \"people\",\n      \"id\": \"9\",\n      \"attributes\": {\n        \"first-name\": \"Dan\",\n        \"last-name\": \"Gebhardt\",\n        \"twitter\": \"dgeb\"\n      },\n      \"links\": {\n        \"self\": \"http://example.com/people/9\"\n      }\n    },\n    {\n      \"type\": \"comments\",\n      \"id\": \"5\",\n      \"attributes\": {\n        \"body\": \"First!\"\n      },\n      \"relationships\": {\n        \"author\": {\n          \"data\": {\n            \"type\": \"people\",\n            \"id\": \"2\"\n          }\n        }\n      },\n      \"links\": {\n        \"self\": \"http://example.com/comments/5\"\n      }\n    },\n    {\n      \"type\": \"comments\",\n      \"id\": \"12\",\n      \"attributes\": {\n        \"body\": \"I like XML better\"\n      },\n      \"relationships\": {\n        \"author\": {\n          \"data\": {\n            \"type\": \"people\",\n            \"id\": \"9\"\n          }\n        }\n      },\n      \"links\": {\n        \"self\": \"http://example.com/comments/12\"\n      }\n    }\n  ]\n}\n```\n\n### Setting the models\n\nYou could create the models like this:\n\n```kotlin\n@JsonApiType(\"articles\")\ndata class Article(\n    var id: String? = null,\n    var title: String = \"\",\n    var author: People? = null,\n    var comments: List\u003cComment\u003e = listOf(),\n)\n\n@JsonApiType(\"people\")\ndata class People(\n    @JsonApiId var id: String,\n    @JsonApiAttribute(\"first-name\") val firstName: String,\n    @JsonApiAttribute(\"last-name\") val lastName: String,\n    @JsonApiAttribute(\"twitter\") val twitter: String = \"\",\n)\n\n@JsonApiType(\"comments\")\ndata class Comment(\n    @JsonApiId val id: String? = null,\n    var body: String = \"\",\n    var author: People? = null,\n)\n```\n\n- Use class or data class, whichever you prefer.\n- Use val or var, whichever you prefer.\n\nTo have custom property name, you must add @JsonApiAttribute and/or @JsonApiRelationship annotations.\n\nProperty with default value is recommended, in case attribute is not present inside json response.\n\nAnnotations @JsonApiAttribute and @JsonApiRelationship contains an \"ignore\" property wich ignore fields in request body\n\n#### Dynamic updates on request body\n\nIf you send your model inside a request, your model will be converted to JSON:API specification with **ALL** attributes and relationships.\n\nIf you only need to send specific attributes/relationships inside your request body, you have to:\n- `implements JsonApiResource` to your model\n- Add updated properties inside `dirtyProperties`\n\nI recommend using delegate class `JsonApiProperty`. Using this, only properties updated **after instancing** will be sent into request body.\n\n```kotlin\n@JsonApiType(\"articles\")\nclass Article(\n    var id: String? = null,\n    title: String = \"\",\n    author: People? = null,\n    comments: List\u003cComment\u003e = listOf(),\n) : JsonApiResource {\n\n    var title: String by JsonApiProperty(title)\n    var author: People? by JsonApiProperty(author)\n    var comments: List\u003cComment\u003e by JsonApiProperty(comments)\n\n    override val dirtyProperties: MutableList\u003cKProperty\u003c*\u003e\u003e = mutableListOf()\n}\n```\n\n```kotlin\nArticle().also {\n    it.title = \"test\"\n    it.author = People(\n        id = \"2\"\n    )\n}\n```\n\n```json\n{\n  \"type\": \"articles\",\n  \"attributes\": {\n    \"title\": \"test\"\n  },\n  \"relationships\": {\n    \"author\": {\n      \"data\": {\n        \"type\": \"people\",\n        \"id\": \"2\"\n      }\n    }\n  }\n}\n```\n\n#### Multi-type relationship\n\n```kotlin\n@JsonApiType(\"people\")\ndata class People(\n    ...\n    val books: List\u003cBook\u003e = listOf()\n)\n\nsealed class Book {\n    @JsonApiType(\"dictionaries\")\n    data class Dictionaries(val id: String, val title: String) : Book()\n\n    @JsonApiType(\"graphic-novels\")\n    data class GraphicNovel(val id: String, val name: String) : Book()\n}\n```\n\n### Define the endpoints\n\nWith Retrofit 2, endpoints are defined inside of an interface using special retrofit annotations to encode details about the parameters and request method.\n\n```kotlin\n@GET(\"articles\")\nsuspend fun getArticles(@QueryMap params: JsonApiParams = JsonApiParams()): JsonApiResponse\u003cList\u003cArticle\u003e\u003e\n\n@GET(\"articles/{id}\")\nsuspend fun getArticle(@Path(\"id\") id: String, @QueryMap params: JsonApiParams = JsonApiParams()): JsonApiResponse\u003cArticle\u003e\n\n@POST(\"articles\")\nsuspend fun createArticle(@Body article: Article): JsonApiResponse\u003cArticle\u003e\n\n@DELETE(\"articles/{id}\")\nsuspend fun deleteArticle(@Path(\"id\") id: String): JsonApiResponse\u003cUnit\u003e\n```\n\n#### JsonApiParams\n\n```kotlin\nJsonApiParams(\n    include = listOf\u003cString\u003e(),\n    fields = mapOf\u003cString, List\u003cString\u003e\u003e(),\n    sort = listOf\u003cString\u003e(),\n    limit = 10,\n    offset = 0,\n    filter = mapOf\u003cString, List\u003cString\u003e\u003e()\n)\n```\n\n#### JsonApiResponse\n\n```kotlin\nwhen (response) {\n    is JsonApiResponse.Success -\u003e {\n        response.headers // okhttp3.Headers\n        response.code // Int (e.g., 2xx)\n\n        response.body.jsonApi?.version // String (e.g., \"1.0\")\n        response.body.included // JSONArray\n        response.body.links?.first // String (e.g., \"http://example.com/...\")\n        response.body.meta // JSONObject\n\n        response.body.raw // String (e.g., \" {\"data\":{\"type\":\"articles\", ... \")\n    }\n    is JsonApiResponse.Error.ServerError -\u003e {\n        response.body.errors.forEach {\n            it.id // String\n            it.links?.about // String\n            it.status // String\n            it.code // String\n            it.title // String\n            it.detail // String\n            it.source?.pointer // String\n            it.source?.parameter // String\n            it.meta // String\n        }\n    }\n    is JsonApiResponse.Error.NetworkError -\u003e {\n        Log.e(\n            TAG,\n            \"Network error: \",\n            response.error // IOException\n        )\n    }\n    is JsonApiResponse.Error.UnknownError -\u003e {\n        Log.e(\n            TAG,\n            \"Unknown error: \",\n            response.error // Throwable\n        )\n    }\n}\n```\n\n### Make the request\n\n#### Fetch a collection\n\n```kotlin\nval response = MainService.build().getArticles(\n    params = JsonApiParams(\n        include = listOf(\"author\")\n    )\n)\nwhen (response) {\n    is JsonApiResponse.Success -\u003e {\n        response.body.data?.forEach {\n            it.title // String (e.g., JSON:API paints my bikeshed!)\n        }\n    }\n    else -\u003e TODO()\n}\n```\n\n#### Fetch a resource\n\n```kotlin\nval response = MainService.build().getArticle(\n    id = id,\n    params = JsonApiParams(\n        include = listOf(\"author\")\n    )\n)\nwhen (response) {\n    is JsonApiResponse.Success -\u003e {\n        response.body.data // Article\n        response.body.data?.title // String (e.g., JSON:API paints my bikeshed!)\n        response.body.data?.author // People\n    }\n    else -\u003e TODO()\n}\n```\n\n#### Create a resource\n\n```kotlin\nval response = TestApiService.build().createArticle(\n    article = Article().also {\n        it.title = \"test\"\n        it.author = People(\n            id = \"2\"\n        )\n    }\n)\nwhen (response) {\n    is JsonApiResponse.Success -\u003e {\n        response.body.data // Article created\n    }\n    else -\u003e TODO()\n}\n```\n\n\n## Contributing\n\nContributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**.\n\n1. Fork the project\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a pull request\n\n\n## Author\n\n- [Lory-Stan TANASI](https://github.com/stantanasi)\n\n\n## License\n\nThis project is licensed under the `Apache-2.0` License - see the [LICENSE](LICENSE) file for details\n\n\u003cp align=\"center\"\u003e\n  \u003cbr /\u003e\n  © 2021 Lory-Stan TANASI. All rights reserved\n\u003c/p\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstantanasi%2Fretrofit-jsonapi-converter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstantanasi%2Fretrofit-jsonapi-converter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstantanasi%2Fretrofit-jsonapi-converter/lists"}