0

When creating the application, I had difficulties with kotlinx serialization. I wrote the code based on the article: https://vtsen.hashnode.dev/simple-rest-api-android-app-in-kotlin-various-http-client-library-implementations and https://www.valueof.io/blog/basic-auth-okhttp-retrofit-dagger Here is my code:


@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    fun providesBaseUrl(): String = "https://api.github.com"

    private val loggingInterceptor = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    private val okHttpBuilder = OkHttpClient.Builder()
        .addInterceptor(loggingInterceptor)

    @Provides
    fun provideApiService(): ApiService {
        okHttpBuilder.addInterceptor(
            BasicAuthInterceptor()
        )

        val contentType = "application/json".toMediaType()

        return Retrofit.Builder()
            .baseUrl("https://api.github.com")
            .addConverterFactory(Json.asConverterFactory(contentType))
            .client(okHttpBuilder.build())
            .build()
            .create(ApiService::class.java)
    }

    @Provides
    @Singleton
    fun provideUserInfoRepository( mainService: ApiService): UserInfoRepository =UserInfoRepository(mainService)

    @Provides
    @Singleton
    fun provideGithubRepositoriesRepository( mainService: ApiService): GithubRepositoriesRepository =GithubRepositoriesRepository(mainService)

}

class BasicAuthInterceptor() : Interceptor {
    private val credentials: String = "Bearer My_Token"

    @Throws(IOException::class)
    override fun intercept(chain: Interceptor.Chain): Response {
        val request: Request = chain.request()
        val authenticatedRequest: Request = request.newBuilder()
            .header("Authorization", credentials).build()
        return chain.proceed(authenticatedRequest)
    }

interface ApiService {

    @GET("user/repos")
    suspend fun getAllUserRepos(): List<GithubRepository>
}

@Serializable
data class GithubRepository (
    val id: Long,

    @SerialName("node_id")
    val nodeID: String,

    val name: String,

    @SerialName("full_name")
    val fullName: String,

    val owner: Owner,
    val private: Boolean,

    @SerialName("html_url")
    val htmlURL: String,

    val description: String,
    val fork: Boolean,
    val url: String,

    @SerialName("archive_url")
    val archiveURL: String,

    @SerialName("assignees_url")
    val assigneesURL: String,

    @SerialName("blobs_url")
    val blobsURL: String,

    @SerialName("branches_url")
    val branchesURL: String,

    @SerialName("collaborators_url")
    val collaboratorsURL: String,

    @SerialName("comments_url")
    val commentsURL: String,

    @SerialName("commits_url")
    val commitsURL: String,

    @SerialName("compare_url")
    val compareURL: String,

    @SerialName("contents_url")
    val contentsURL: String,

    @SerialName("contributors_url")
    val contributorsURL: String,

    @SerialName("deployments_url")
    val deploymentsURL: String,

    @SerialName("downloads_url")
    val downloadsURL: String,

    @SerialName("events_url")
    val eventsURL: String,

    @SerialName("forks_url")
    val forksURL: String,

    @SerialName("git_commits_url")
    val gitCommitsURL: String,

    @SerialName("git_refs_url")
    val gitRefsURL: String,

    @SerialName("git_tags_url")
    val gitTagsURL: String,

    @SerialName("git_url")
    val gitURL: String,

    @SerialName("issue_comment_url")
    val issueCommentURL: String,

    @SerialName("issue_events_url")
    val issueEventsURL: String,

    @SerialName("issues_url")
    val issuesURL: String,

    @SerialName("keys_url")
    val keysURL: String,

    @SerialName("labels_url")
    val labelsURL: String,

    @SerialName("languages_url")
    val languagesURL: String,

    @SerialName("merges_url")
    val mergesURL: String,

    @SerialName("milestones_url")
    val milestonesURL: String,

    @SerialName("notifications_url")
    val notificationsURL: String,

    @SerialName("pulls_url")
    val pullsURL: String,

    @SerialName("releases_url")
    val releasesURL: String,

    @SerialName("ssh_url")
    val sshURL: String,

    @SerialName("stargazers_url")
    val stargazersURL: String,

    @SerialName("statuses_url")
    val statusesURL: String,

    @SerialName("subscribers_url")
    val subscribersURL: String,

    @SerialName("subscription_url")
    val subscriptionURL: String,

    @SerialName("tags_url")
    val tagsURL: String,

    @SerialName("teams_url")
    val teamsURL: String,

    @SerialName("trees_url")
    val treesURL: String,

    @SerialName("clone_url")
    val cloneURL: String,

    @SerialName("mirror_url")
    val mirrorURL: String,

    @SerialName("hooks_url")
    val hooksURL: String,

    @SerialName("svn_url")
    val svnURL: String,

    val homepage: String,
    val language: JsonElement? = null,

    @SerialName("forks_count")
    val forksCount: Long,

    @SerialName("stargazers_count")
    val stargazersCount: Long,

    @SerialName("watchers_count")
    val watchersCount: Long,

    val size: Long,

    @SerialName("default_branch")
    val defaultBranch: String,

    @SerialName("open_issues_count")
    val openIssuesCount: Long,

    @SerialName("is_template")
    val isTemplate: Boolean,

    val topics: List<String>,

    @SerialName("has_issues")
    val hasIssues: Boolean,

    @SerialName("has_projects")
    val hasProjects: Boolean,

    @SerialName("has_wiki")
    val hasWiki: Boolean,

    @SerialName("has_pages")
    val hasPages: Boolean,

    @SerialName("has_downloads")
    val hasDownloads: Boolean,

    val archived: Boolean,
    val disabled: Boolean,
    val visibility: String,

    @SerialName("pushed_at")
    val pushedAt: String,

    @SerialName("created_at")
    val createdAt: String,

    @SerialName("updated_at")
    val updatedAt: String,

    val permissions: Permissions,

    @SerialName("allow_rebase_merge")
    val allowRebaseMerge: Boolean,

    @SerialName("template_repository")
    val templateRepository: JsonElement? = null,

    @SerialName("temp_clone_token")
    val tempCloneToken: String,

    @SerialName("allow_squash_merge")
    val allowSquashMerge: Boolean,

    @SerialName("allow_auto_merge")
    val allowAutoMerge: Boolean,

    @SerialName("delete_branch_on_merge")
    val deleteBranchOnMerge: Boolean,

    @SerialName("allow_merge_commit")
    val allowMergeCommit: Boolean,

    @SerialName("subscribers_count")
    val subscribersCount: Long,

    @SerialName("network_count")
    val networkCount: Long,

    val license: License,
    val forks: Long,

    @SerialName("open_issues")
    val openIssues: Long,

    val watchers: Long
)

@Serializable
data class License (
    val key: String,
    val name: String,
    val url: String,

    @SerialName("spdx_id")
    val spdxID: String,

    @SerialName("node_id")
    val nodeID: String,

    @SerialName("html_url")
    val htmlURL: String
)

@Serializable
data class Owner (
    val login: String,
    val id: Long,

    @SerialName("node_id")
    val nodeID: String,

    @SerialName("avatar_url")
    val avatarURL: String,

    @SerialName("gravatar_id")
    val gravatarID: String,

    val url: String,

    @SerialName("html_url")
    val htmlURL: String,

    @SerialName("followers_url")
    val followersURL: String,

    @SerialName("following_url")
    val followingURL: String,

    @SerialName("gists_url")
    val gistsURL: String,

    @SerialName("starred_url")
    val starredURL: String,

    @SerialName("subscriptions_url")
    val subscriptionsURL: String,

    @SerialName("organizations_url")
    val organizationsURL: String,

    @SerialName("repos_url")
    val reposURL: String,

    @SerialName("events_url")
    val eventsURL: String,

    @SerialName("received_events_url")
    val receivedEventsURL: String,

    val type: String,

    @SerialName("site_admin")
    val siteAdmin: Boolean
)

@Serializable
data class Permissions (
    val admin: Boolean,
    val push: Boolean,
    val pull: Boolean
)


I should get the answer in the form of JSON:


[
  {
    "id": 1296269,
    "node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
    "name": "Hello-World",
    "full_name": "octocat/Hello-World",
    "owner": {
      "login": "octocat",
      "id": 1,
      "node_id": "MDQ6VXNlcjE=",
      "avatar_url": "https://github.com/images/error/octocat_happy.gif",
      "gravatar_id": "",
      "url": "https://api.github.com/users/octocat",
      "html_url": "https://github.com/octocat",
      "followers_url": "https://api.github.com/users/octocat/followers",
      "following_url": "https://api.github.com/users/octocat/following{/other_user}",
      "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
      "organizations_url": "https://api.github.com/users/octocat/orgs",
      "repos_url": "https://api.github.com/users/octocat/repos",
      "events_url": "https://api.github.com/users/octocat/events{/privacy}",
      "received_events_url": "https://api.github.com/users/octocat/received_events",
      "type": "User",
      "site_admin": false
    },
    "private": false,
    "html_url": "https://github.com/octocat/Hello-World",
    "description": "This your first repo!",
    "fork": false,
    "url": "https://api.github.com/repos/octocat/Hello-World",
    "archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}",
    "assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}",
    "blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}",
    "branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}",
    "collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}",
    "comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}",
    "commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}",
    "compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}",
    "contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}",
    "contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors",
    "deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments",
    "downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads",
    "events_url": "https://api.github.com/repos/octocat/Hello-World/events",
    "forks_url": "https://api.github.com/repos/octocat/Hello-World/forks",
    "git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}",
    "git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}",
    "git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}",
    "git_url": "git:github.com/octocat/Hello-World.git",
    "issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}",
    "issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}",
    "issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}",
    "keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}",
    "labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}",
    "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages",
    "merges_url": "https://api.github.com/repos/octocat/Hello-World/merges",
    "milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}",
    "notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}",
    "pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}",
    "releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}",
    "ssh_url": "git@github.com:octocat/Hello-World.git",
    "stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers",
    "statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}",
    "subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers",
    "subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription",
    "tags_url": "https://api.github.com/repos/octocat/Hello-World/tags",
    "teams_url": "https://api.github.com/repos/octocat/Hello-World/teams",
    "trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}",
    "clone_url": "https://github.com/octocat/Hello-World.git",
    "mirror_url": "git:git.example.com/octocat/Hello-World",
    "hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks",
    "svn_url": "https://svn.github.com/octocat/Hello-World",
    "homepage": "https://github.com",
    "language": null,
    "forks_count": 9,
    "stargazers_count": 80,
    "watchers_count": 80,
    "size": 108,
    "default_branch": "master",
    "open_issues_count": 0,
    "is_template": true,
    "topics": [
      "octocat",
      "atom",
      "electron",
      "api"
    ],
    "has_issues": true,
    "has_projects": true,
    "has_wiki": true,
    "has_pages": false,
    "has_downloads": true,
    "archived": false,
    "disabled": false,
    "visibility": "public",
    "pushed_at": "2011-01-26T19:06:43Z",
    "created_at": "2011-01-26T19:01:12Z",
    "updated_at": "2011-01-26T19:14:43Z",
    "permissions": {
      "admin": false,
      "push": false,
      "pull": true
    },
    "allow_rebase_merge": true,
    "template_repository": null,
    "temp_clone_token": "ABTLWHOULUVAXGTRYU7OC2876QJ2O",
    "allow_squash_merge": true,
    "allow_auto_merge": false,
    "delete_branch_on_merge": true,
    "allow_merge_commit": true,
    "subscribers_count": 42,
    "network_count": 0,
    "license": {
      "key": "mit",
      "name": "MIT License",
      "url": "https://api.github.com/licenses/mit",
      "spdx_id": "MIT",
      "node_id": "MDc6TGljZW5zZW1pdA==",
      "html_url": "https://github.com/licenses/mit"
    },
    "forks": 1,
    "open_issues": 1,
    "watchers": 1
  }
]

When I use GsonConverterFactory then I get the correct result:


return Retrofit.Builder()
            .baseUrl("https://api.github.com")
            .addConverterFactory(GsonConverterFactory.create())
            .client(okHttpBuilder.build())
            .build()
            .create(ApiService::class.java)


  • can you elaborate on "I don't get data" part? I don't think serializer fails silently. – Pawel Aug 03 '23 at 08:57
  • When executing the code, I don't get a response string in logcat ` Log.i("abc1", repository.getGithubRepositories(token).toString()` ` class GithubRepositoriesRepository @Inject constructor( private val apiService: ApiService ) { suspend fun getGithubRepositories(token: String) = apiService.getAllUserRepos(/*token*/) }` – Влад Михнёнок Aug 03 '23 at 09:15

0 Answers0