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)