package com.example.myapp.data.remote
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.*
import java.util.concurrent.TimeUnit
interface ApiService {
@GET("posts")
suspend fun getPosts(
@Query("page") page: Int = 1,
@Query("per_page") perPage: Int = 20
): PostsResponse
@GET("posts/{id}")
suspend fun getPost(@Path("id") postId: Int): PostResponse
@POST("posts")
suspend fun createPost(@Body request: CreatePostRequest): PostResponse
@PUT("posts/{id}")
suspend fun updatePost(
@Path("id") postId: Int,
@Body request: UpdatePostRequest
): PostResponse
@DELETE("posts/{id}")
suspend fun deletePost(@Path("id") postId: Int)
@GET("posts/{id}/comments")
suspend fun getComments(@Path("id") postId: Int): CommentsResponse
@POST("posts/{id}/like")
suspend fun likePost(@Path("id") postId: Int): LikeResponse
@DELETE("posts/{id}/like")
suspend fun unlikePost(@Path("id") postId: Int)
@GET("search")
suspend fun search(@Query("q") query: String): SearchResponse
}
data class PostsResponse(
val posts: List<Post>,
val meta: Meta
)
data class PostResponse(
val post: Post
)
data class CommentsResponse(
val comments: List<Comment>
)
data class LikeResponse(
val likesCount: Int
)
data class SearchResponse(
val results: List<Post>
)
data class Meta(
val page: Int,
val perPage: Int,
val total: Int
)
data class CreatePostRequest(
val title: String,
val body: String
)
data class UpdatePostRequest(
val title: String?,
val body: String?
)
package com.example.myapp.di
import com.example.myapp.data.remote.ApiService
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideMoshi(): Moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
@Provides
@Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor =
HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
}
@Provides
@Singleton
fun provideAuthInterceptor(
tokenManager: TokenManager
): AuthInterceptor = AuthInterceptor(tokenManager)
@Provides
@Singleton
fun provideOkHttpClient(
loggingInterceptor: HttpLoggingInterceptor,
authInterceptor: AuthInterceptor
): OkHttpClient = OkHttpClient.Builder()
.addInterceptor(authInterceptor)
.addInterceptor(loggingInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build()
@Provides
@Singleton
fun provideRetrofit(
okHttpClient: OkHttpClient,
moshi: Moshi
): Retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/v1/")
.client(okHttpClient)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
@Provides
@Singleton
fun provideApiService(retrofit: Retrofit): ApiService =
retrofit.create(ApiService::class.java)
}
class AuthInterceptor(
private val tokenManager: TokenManager
) : okhttp3.Interceptor {
override fun intercept(chain: okhttp3.Interceptor.Chain): okhttp3.Response {
val original = chain.request()
val token = tokenManager.getToken()
val request = if (token != null) {
original.newBuilder()
.header("Authorization", "Bearer $token")
.build()
} else {
original
}
return chain.proceed(request)
}
}
Retrofit simplifies HTTP networking with type-safe API definitions. I define service interfaces with annotated methods—@GET, @POST, @PUT, @DELETE. Path parameters use @Path, query params use @Query, and request bodies use @Body. Retrofit converts responses to Kotlin objects automatically with Gson or Moshi. For coroutines, I mark methods as suspend. Interceptors add headers, log requests, or handle authentication. OkHttpClient customizes timeout, caching, and SSL. Call adapters enable RxJava or Flow. Error handling uses try/catch with suspend functions or Result types. Retrofit's clean API reduces boilerplate and integrates seamlessly with modern Android architectures.