Skip to content

Instantly share code, notes, and snippets.

@arafaysaleem
Last active July 3, 2022 15:14
Show Gist options
  • Save arafaysaleem/90fd380f972c2392ca5e0caa27910cbb to your computer and use it in GitHub Desktop.
Save arafaysaleem/90fd380f972c2392ca5e0caa27910cbb to your computer and use it in GitHub Desktop.
Generic Dio Service Wrapper
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
// Exceptions
import './custom_exception.dart';
// Helpers
import '../../helpers/typedefs.dart';
// Models
import 'response_model.dart';
/// A service class that wraps the [Dio] instance and provides methods for
/// basic network requests.
class DioService {
/// An instance of [Dio] for executing network requests.
final Dio _dio;
/// A set of cache options to be used for each request
final CacheOptions? globalCacheOptions;
/// An instance of [CancelToken] used to pre-maturely cancel
/// network requests.
final CancelToken _cancelToken;
/// A public constructor that is used to create a Dio service and initialize
/// the underlying [Dio] client.
///
/// * [interceptors]: An [Iterable] for attaching custom
/// [Interceptor]s to the underlying [_dio] client.
/// * [httpClientAdapter]: Replaces the underlying [HttpClientAdapter] with
/// this custom one.
DioService({
required Dio dioClient,
this.globalCacheOptions,
Iterable<Interceptor>? interceptors,
HttpClientAdapter? httpClientAdapter,
}) : _dio = dioClient,
_cancelToken = CancelToken() {
if (interceptors != null) _dio.interceptors.addAll(interceptors);
if (httpClientAdapter != null) _dio.httpClientAdapter = httpClientAdapter;
}
/// This method invokes the [cancel()] method on either the input
/// [cancelToken] or internal [_cancelToken] to pre-maturely end all
/// requests attached to this token.
void cancelRequests({CancelToken? cancelToken}) {
if (cancelToken == null) {
_cancelToken.cancel('Cancelled');
} else {
cancelToken.cancel();
}
}
/// This method sends a `GET` request to the [endpoint], **decodes**
/// the response and returns a parsed [ResponseModel] with a body of type [R].
///
/// Any errors encountered during the request are caught and a custom
/// [CustomException] is thrown.
///
/// [queryParams] holds any query parameters for the request.
///
/// [cancelToken] is used to cancel the request pre-maturely. If null,
/// the **default** [cancelToken] inside [DioService] is used.
///
/// [cacheOptions] are special cache instructions that can merge and override
/// the [globalCacheOptions].
///
/// [options] are special instructions that can be merged with the request.
Future<ResponseModel<R>> get<R>({
required String endpoint,
JSON? queryParams,
Options? options,
CacheOptions? cacheOptions,
CancelToken? cancelToken,
}) async {
final response = await _dio.get<JSON>(
endpoint,
queryParameters: queryParams,
options: _mergeDioAndCacheOptions(
dioOptions: options,
cacheOptions: cacheOptions,
),
cancelToken: cancelToken ?? _cancelToken,
);
return ResponseModel<R>.fromJson(response.data!);
}
/// This method sends a `POST` request to the [endpoint], **decodes**
/// the response and returns a parsed [ResponseModel] with a body of type [R].
///
/// Any errors encountered during the request are caught and a custom
/// [CustomException] is thrown.
///
/// The [data] contains body for the request.
///
/// [cancelToken] is used to cancel the request pre-maturely. If null,
/// the **default** [cancelToken] inside [DioService] is used.
///
/// [options] are special instructions that can be merged with the request.
Future<ResponseModel<R>> post<R>({
required String endpoint,
JSON? data,
Options? options,
CancelToken? cancelToken,
}) async {
final response = await _dio.post<JSON>(
endpoint,
data: data,
options: options,
cancelToken: cancelToken ?? _cancelToken,
);
return ResponseModel<R>.fromJson(response.data!);
}
/// This method sends a `PATCH` request to the [endpoint], **decodes**
/// the response and returns a parsed [ResponseModel] with a body of type [R].
///
/// Any errors encountered during the request are caught and a custom
/// [CustomException] is thrown.
///
/// The [data] contains body for the request.
///
/// [cancelToken] is used to cancel the request pre-maturely. If null,
/// the **default** [cancelToken] inside [DioService] is used.
///
/// [options] are special instructions that can be merged with the request.
Future<ResponseModel<R>> patch<R>({
required String endpoint,
JSON? data,
Options? options,
CancelToken? cancelToken,
}) async {
final response = await _dio.patch<JSON>(
endpoint,
data: data,
options: options,
cancelToken: cancelToken ?? _cancelToken,
);
return ResponseModel<R>.fromJson(response.data!);
}
/// This method sends a `DELETE` request to the [endpoint], **decodes**
/// the response and returns a parsed [ResponseModel] with a body of type [R].
///
/// Any errors encountered during the request are caught and a custom
/// [CustomException] is thrown.
///
/// The [data] contains body for the request.
///
/// [cancelToken] is used to cancel the request pre-maturely. If null,
/// the **default** [cancelToken] inside [DioService] is used.
///
/// [options] are special instructions that can be merged with the request.
Future<ResponseModel<R>> delete<R>({
required String endpoint,
JSON? data,
Options? options,
CancelToken? cancelToken,
}) async {
final response = await _dio.delete<JSON>(
endpoint,
data: data,
options: options,
cancelToken: cancelToken ?? _cancelToken,
);
return ResponseModel<R>.fromJson(response.data!);
}
/// A utility method used to merge together [Options]
/// and [CacheOptions].
///
/// Returns an [Options] object with [CacheOptions] stored
/// in the [options.extra] key.
Options? _mergeDioAndCacheOptions({
Options? dioOptions,
CacheOptions? cacheOptions,
}) {
if (dioOptions == null && cacheOptions == null) {
return null;
} else if (dioOptions == null && cacheOptions != null) {
return cacheOptions.toOptions();
} else if (dioOptions != null && cacheOptions == null) {
return dioOptions;
}
final _cacheOptionsMap = cacheOptions!.toExtra();
final options = dioOptions!.copyWith(
extra: <String, dynamic>{...dioOptions.extra!, ..._cacheOptionsMap},
);
return options;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment