Skip to content

Instantly share code, notes, and snippets.

@dev4jam
Created March 21, 2022 06:57
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save dev4jam/ce094af46be6150cd0d20322e37dd958 to your computer and use it in GitHub Desktop.
Save dev4jam/ce094af46be6150cd0d20322e37dd958 to your computer and use it in GitHub Desktop.
Full source code of the Network Service
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:io';
part 'NetworkRequestBody.freezed.dart';
part 'NetworkResponse.freezed.dart';
class AccessTokenResponse {
String? accessToken;
AccessTokenResponse.fromJson(Map<String, dynamic> json) {
accessToken = json['access_token'];
}
}
@freezed
class NetworkRequestBody with _$NetworkRequestBody {
const factory NetworkRequestBody.empty() = Empty;
const factory NetworkRequestBody.json(Map<String, dynamic> data) = Json;
const factory NetworkRequestBody.text(String data) = Text;
}
enum NetworkRequestType { GET, POST, PUT, PATCH, DELETE }
class NetworkRequest {
const NetworkRequest({
required this.type,
required this.path,
required this.data,
this.queryParams,
this.headers,
});
final NetworkRequestType type;
final String path;
final NetworkRequestBody data;
final Map<String, dynamic>? queryParams;
final Map<String, String>? headers;
}
@freezed
class NetworkResponse<Model> with _$NetworkResponse {
const factory NetworkResponse.ok(Model data) = Ok;
const factory NetworkResponse.invalidParameters(String message) = InvalidParameters;
const factory NetworkResponse.noAuth(String message) = NoAuth; //401
const factory NetworkResponse.noAccess(String message) = NoAccess; //403
const factory NetworkResponse.badRequest(String message) = BadRequest; //400
const factory NetworkResponse.notFound(String message) = NotFound; //404
const factory NetworkResponse.conflict(String message) = Conflict; //409
const factory NetworkResponse.noData(String message) = NoData; //500
}
class _PreparedNetworkRequest<Model> {
const _PreparedNetworkRequest(
this.request,
this.parser,
this.dio,
this.headers,
this.onSendProgress,
this.onReceiveProgress,
);
final NetworkRequest request;
final Model Function(Map<String, dynamic>) parser;
final Dio dio;
final Map<String, dynamic> headers;
final ProgressCallback? onSendProgress;
final ProgressCallback? onReceiveProgress;
}
Future<NetworkResponse<Model>> executeRequest<Model>(
_PreparedNetworkRequest request,
) async {
try {
dynamic body = request.request.data.whenOrNull(
json: (data) => data,
text: (data) => data,
);
final response = await request.dio.request(
request.request.path,
data: body,
queryParameters: request.request.queryParams,
options: Dio.Options(
method: request.request.type.name,
headers: request.headers,
),
onSendProgress: request.onSendProgress,
onReceiveProgress: request.onReceiveProgress,
);
return NetworkResponse.ok(request.parser(response.data));
} on Dio.DioError catch (error) {
final errorText = error.toString();
if (error.requestOptions.cancelToken!.isCancelled) {
return NetworkResponse.noData(errorText);
}
switch (error.response?.statusCode) {
case 400:
return NetworkResponse.badRequest(errorText);
case 401:
return NetworkResponse.noAuth(errorText);
case 403:
return NetworkResponse.noAccess(errorText);
case 404:
return NetworkResponse.notFound(errorText);
case 409:
return NetworkResponse.conflict(errorText);
default:
return NetworkResponse.noData(errorText);
}
} catch (error) {
return NetworkResponse.noData(error.toString());
}
}
class NetworkService {
NetworkService({
required this.baseUrl,
dioClient,
httpHeaders,
}) : this._dio = dioClient,
this._headers = httpHeaders ?? {};
Dio? _dio;
final String baseUrl;
Map<String, String> _headers;
Future<Dio> _getDefaultDioClient() async {
_headers['content-type'] = 'application/json; charset=utf-8';
final dio = Dio()
..options.baseUrl = baseUrl
..options.headers = _headers
..options.connectTimeout = 5000 // 5 seconds
..options.receiveTimeout = 3000; // 3 seconds
}
return dio;
}
void addBasicAuth(String accessToken) {
_headers['Authorization'] = 'Bearer $accessToken';
}
Future<NetworkResponse<Model>> execute<Model>(
NetworkRequest request,
Model Function(Map<String, dynamic>) parser, {
ProgressCallback? onSendProgress = null,
ProgressCallback? onReceiveProgress = null,
}) async {
if (_dio == null) {
_dio = await _getDefaultDioClient();
}
final req = _PreparedNetworkRequest<Model>(
request,
parser,
_dio!,
{..._headers, ...(request.headers ?? {})},
onSendProgress,
onReceiveProgress,
);
final result = await compute(
executeRequest<Model>,
req,
);
return result;
}
}
@AliJ91
Copy link

AliJ91 commented Oct 10, 2022

line 14 till line 19, what's happening there? also I'm getting an error after each "="
like : "The name 'Json' isn't a type and can't be used in a redirected constructor"

@Maus3rSR
Copy link

Maus3rSR commented Mar 21, 2023

line 14 till line 19, what's happening there? also I'm getting an error after each "=" like : "The name 'Json' isn't a type and can't be used in a redirected constructor"

It's about freezed package which generate factory constructors initializers I think.
Same for NetworkResponse.

@dev4jam
Copy link
Author

dev4jam commented Mar 21, 2023

@AliJ91 yes, it's Freezed package annotation. Basically it creates states for your component. You can define them as classes as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment