Agent Skill
2/7/2026repository-remote
Implements Repository with remote API only. Use when the user asks to write RepositoryImpl for API, create repository for network calls, Retrofit, HTTP, backend, safeApiCall, ApiResult, or add a new API-backed repository. Enforces interface + RepositoryImpl, safeApiCall for all remote calls only (not Room/DAO), Hilt binding.
T
thinhtt264
0GitHub Stars
1Views
npx skills add thinhtt264/Snaplet-App
SKILL.md
| Name | repository-remote |
| Description | Implements Repository with remote API only. Use when the user asks to write RepositoryImpl for API, create repository for network calls, Retrofit, HTTP, backend, safeApiCall, ApiResult, or add a new API-backed repository. Enforces interface + RepositoryImpl, safeApiCall for all remote calls only (not Room/DAO), Hilt binding. |
name: repository-remote description: Implements Repository with remote API only. Use when the user asks to write RepositoryImpl for API, create repository for network calls, Retrofit, HTTP, backend, safeApiCall, ApiResult, fold, onSuccess, onFailure, or add a new API-backed repository. Enforces interface + RepositoryImpl, safeApiCall for all remote calls only (not Room/DAO), Hilt binding. Use fold for returning/transforming values; use onSuccess/onFailure for side effects only.
Repository with Remote API (safeApiCall)
When to use this skill
- User asks to write Repository / RepositoryImpl for API calls (Retrofit, network, HTTP, backend).
- User asks to add a new repository for a feature that calls the backend.
- Do not use for repository that only reads/writes Room DAO (use skill
repository-room).
Required rules
1. Always split Interface + Implementation
- Interface: name
XxxRepository, declare suspend functions returningApiResult<T>for every API call. - Implementation: name
XxxRepositoryImpl,@Singleton, inject API service (and other deps if needed), implement interface.
2. Wrap every API call with safeApiCall
- Use safeApiCall only for remote API (Retrofit). Do not use for Room DAO or local logic.
- Import:
com.thinh.snaplet.utils.network.safeApiCall - API service must return
Response<BaseResponse<T>>(project backend format).
3. Hilt binding
- In RepositoryModule: use
@Bindsabstract fun bindXxxRepository(impl: XxxRepositoryImpl): XxxRepository. @InstallIn(SingletonComponent::class), impl is@Singleton.
safeApiCall – detailed description
Project has 2 overloads:
Overload 1: No transform (return API type as-is)
suspend fun <T> safeApiCall(
apiCall: suspend () -> Response<BaseResponse<T>>,
onSuccess: suspend (T) -> Unit = {}
): ApiResult<T>
- apiCall: lambda that calls API (e.g.
{ apiService.getUser(id) }). Do not catch exceptions inside. - onSuccess: (optional) runs when API is 2xx and has body; use for saving token, updating cache, etc.
- Return:
ApiResult.Success(data)if 2xx and body has data, elseApiResult.Failure(ApiError).
Example:
override suspend fun getUserProfile(userName: String): ApiResult<UserProfile> {
return safeApiCall(
apiCall = { apiService.getUserProfile(userName) }
)
}
Overload 2: With transform (map DTO → domain / expose part of response)
suspend fun <T, R> safeApiCall(
apiCall: suspend () -> Response<BaseResponse<T>>,
onSuccess: suspend (T) -> Unit = {},
transform: (T) -> R
): ApiResult<R>
- apiCall: same as above.
- onSuccess: receives T (raw API data), use for side-effects (save token, profile, etc.).
- transform: map T → R; ViewModel receives R (e.g. only
Userinstead of fullLoginResponse). - Return:
ApiResult.Success(transform(data))on success.
Example (login: API returns TokenResponse + User, expose only User):
override suspend fun login(email: String, password: String): ApiResult<UserProfile> {
return safeApiCall(
apiCall = { apiService.login(body = LoginRequest(email, password)) },
onSuccess = { result ->
dataStoreManager.saveTokens(result.token.accessToken, result.token.refreshToken)
dataStoreManager.saveUserProfile(result.user)
_authState.value = AuthState.Authenticated
},
transform = { response -> response.user }
)
}
Notes when using safeApiCall
- Do not call API directly and try/catch in repository; always wrap in
safeApiCall. - onSuccess is for side-effects (save local, update state); transform is only for changing return type.
- API error (4xx/5xx) or exception →
ApiResult.Failure(ApiError)(message from backend or default by http code). - Repository function return type: always
ApiResult<T>(orApiResult<R>if using transform) for every API call.
ApiResult: fold vs onSuccess / onFailure (consuming results)
- fold: use when you need to use the returned data — get one value from the result (both success and failure return/transform to the same type). Use to assign or return that value.
- onSuccess / onFailure: use to transform or handle the result per branch (side effects, update state, log, emit event). When you don't need a single value from the result, use onSuccess/onFailure.
Example: need one value → val x = result.fold(onSuccess = { it }, onFailure = { null }). Only side effects (e.g. refresh + update loading) → result.onSuccess { ... }.onFailure { ... }.
Suggested file structure
data/repository/
XxxRepository.kt # interface
XxxRepositoryImpl.kt # class, @Singleton, safeApiCall per API
di/
RepositoryModule.kt # @Binds XxxRepositoryImpl -> XxxRepository
Full example (remote only)
XxxRepository.kt
interface XxxRepository {
suspend fun fetchItem(id: String): ApiResult<Item>
suspend fun submitItem(item: Item): ApiResult<Unit>
}
XxxRepositoryImpl.kt
@Singleton
class XxxRepositoryImpl @Inject constructor(
private val apiService: ApiService
) : XxxRepository {
override suspend fun fetchItem(id: String): ApiResult<Item> {
return safeApiCall(apiCall = { apiService.getItem(id) })
}
override suspend fun submitItem(item: Item): ApiResult<Unit> {
return safeApiCall(
apiCall = { apiService.postItem(item) },
onSuccess = { /* optional: cache, analytics */ },
transform = { }
)
}
}
RepositoryModule.kt
@Binds
@Singleton
abstract fun bindXxxRepository(impl: XxxRepositoryImpl): XxxRepository
Checklist
- Interface
XxxRepositoryand classXxxRepositoryImplexist. - Every API call in Impl is wrapped in
safeApiCall(no direct API call). - Repository functions return
ApiResult<T>for API calls. - Impl → Interface bound in
RepositoryModule. - Do not use safeApiCall for Room/DAO (use skill
repository-roomfor local DB). - When consuming
ApiResult: use fold when you need the returned data (one value from both branches); otherwise use onSuccess/onFailure to handle/transform the result.
Skills Info
Original Name:repository-remoteAuthor:thinhtt264
Download