A data repository for flutter, manages both local and remote api access
Features
see sample here
Getting started
Define your implementation of local and remote repositories.
The local repository manages caching and retrieving data localy, while the remote repository manages retrieving data from a remote source. I would recommend using GetIt for this
GetIt.I.registerSingleton<LocalRepository>(HiveRepository());
GetIt.I.registerSingleton<RemoteRepository>(
RemoteRepository((HttpApiProvider())));
create an API service class. This is just a class where you define your API requests
class PostApi {
ApiRequest<Post, Post> create(CreatePostDto body) {
return ApiRequest<Post, Post>(
baseUrl: baseUrl,
path: ApiUrls.department,
method: ApiMethods.post,
body: body.toJson,
dataKey: 'data',
error: ErrorDescription(),
interceptors: [
HeaderInterceptor({
'Authorization': 'Bearer $token',
"Content-Type": "application/json",
"Accept": "application/json",
}),
JsonInterceptor<ErrorModel>(DepartmentModels.factories),
NetworkDurationInterceptor(),
]);
}
}
Create a resository class and extend the
DataRepository
class
Here you need to initialize your local and remote repository implementations.
class PostRepository extends DataRepository {
final _api = PostApi();
PostRepository()
: super(GetIt.I<LocalRepository>(), GetIt.I<RemoteRepository>());
Future<ApiResponse<Post, Post>> createPost(CreatePostDto body) async {
return await handleRequest(_api.create(body));
}
you can use your repository in you view model to fetch data and manage state based on the response.
void createPost() async {
emit(state.loading());
final response = await _repository.createPost(CreatePostDto(
title: state.title ?? '',
content: state.content ?? '',
image: state.image ?? ''));
if (response.isSuccessful) {
emit(PostCreated('Register success', state));
} else {
// print((response.error as ApiError).message);
emit(ErrorState(response.error as ApiError, state));
}
}
caching
in your repository, you can set CacheDescription
to define if you want request to be cached.
you set the key, and the lifespan
Future<ApiResponse<List<Post>, Post>> getPost() async {
return await handleRequest(_api.getPost(),
cache: CacheDescription('posts-list',
lifeSpan: CacheDescription.oneMinute));
}
interceptors
You can define interceptors to intercept request or response objects
Interceptors run before a request is fulfilled, and after response is gotten.
To create an interceptor, extend the ApiInterceptor
class and override onRequest
to
intercept request and onResponse
to intercept response and onError
to intercept request error.
class NetworkDurationInterceptor extends ApiInterceptor {
Map<String, int> timestamp = {};
@override
ApiResponse<ResponseType, InnerType> onResponse<ResponseType, InnerType>(
ApiResponse<ResponseType, InnerType> response) {
if (kDebugMode) {
print(
'NetworkDurationInterceptor ${response.statusCode}, ${response.request.requestId}, $timestamp ${timestamp[response.request.requestId]}');
}
var duration = DateTime.now().millisecondsSinceEpoch -
(timestamp.remove(response.request.requestId) ?? 00);
if (kDebugMode) {
print('request completed in $duration milliseconds');
}
return response.copyWith(extra: {...?response.extra, 'duration': duration});
}
@override
ApiRequest<ResponseType, InnerType> onRequest<ResponseType, InnerType>(
ApiRequest<ResponseType, InnerType> request) {
timestamp
.addAll({request.requestId: DateTime.now().millisecondsSinceEpoch});
return request; //.copyWith(: );
}
@override
ApiResponse<ResponseType, InnerType> onError<ResponseType, InnerType>(
ApiResponse<ResponseType, InnerType> response) {
var duration = DateTime.now().millisecondsSinceEpoch -
(timestamp.remove(response.request.requestId) ?? 00);
if (kDebugMode) {
print('request completed with error in $duration milliseconds');
}
return response.copyWith(extra: {...?response.extra, 'duration': duration});
}
}
Check the example app for sample code More examples comming soon
Libraries
- cache/cache_description
- cache/cache_manager
- cache/cache_mixin
- cache/index
- data_repository
- local/index
- local/local_repository
- local/map_repository
- models/api_error
- models/index
- models/json_factory
- models/pagination
- remote/api_client
- remote/api_methods
- remote/api_request
- remote/api_response
- remote/base_api_service
- remote/file_field
- remote/index
- remote/interceptors/api_interceptor
- remote/interceptors/header_interceptor
- remote/interceptors/index
- remote/pagination_handler
- remote/provider/api_provider
- remote/provider/providers/chopper_api_provider
- remote/provider/providers/dio_api_provider
- remote/provider/providers/http_api_provider
- remote/provider/providers/http_override
- remote/remote_repository
- utils/api_config
- utils/exception_formater
- utils/extensions/dynamic
- utils/extensions/index
- utils/extensions/map
- utils/extensions/num
- utils/extensions/string
- utils/index
- utils/json_utils