refactor: Clean up ApiClient code structure and improve readability
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ class ApiClient {
|
|||||||
ApiClient({http.Client? client})
|
ApiClient({http.Client? client})
|
||||||
: baseUrl = const String.fromEnvironment(
|
: baseUrl = const String.fromEnvironment(
|
||||||
'API_BASE_URL',
|
'API_BASE_URL',
|
||||||
defaultValue: '/api',
|
defaultValue: '/api',
|
||||||
),
|
),
|
||||||
_client = client ?? http.Client();
|
_client = client ?? http.Client();
|
||||||
|
|
||||||
@@ -23,45 +23,33 @@ class ApiClient {
|
|||||||
if (token != null) 'Authorization': 'Bearer $token',
|
if (token != null) 'Authorization': 'Bearer $token',
|
||||||
};
|
};
|
||||||
|
|
||||||
Future<dynamic> getJson(String path, {String? token}) async {
|
Future<dynamic> getJson(String path, {String? token}) async {
|
||||||
final response = await _client.get(
|
final response = await _client.get(
|
||||||
Uri.parse('$baseUrl$path'),
|
Uri.parse('$baseUrl$path'),
|
||||||
headers: _headers(token: token),
|
headers: _headers(token: token),
|
||||||
);
|
);
|
||||||
return _decodeOrNull(_guardResponse(response));
|
return _decodeOrNull(_guardResponse(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> postJson(
|
Future<dynamic> postJson(String path, {Object? body, String? token}) async {
|
||||||
String path, {
|
final response = await _client.post(
|
||||||
Object? body,
|
Uri.parse('$baseUrl$path'),
|
||||||
String? token,
|
headers: _headers(token: token),
|
||||||
}) async {
|
body: body == null ? null : jsonEncode(body),
|
||||||
final response = await _client.post(
|
);
|
||||||
Uri.parse('$baseUrl$path'),
|
return _decodeOrNull(_guardResponse(response));
|
||||||
headers: _headers(token: token),
|
}
|
||||||
body: body == null ? null : jsonEncode(body),
|
|
||||||
);
|
|
||||||
return _decodeOrNull(_guardResponse(response));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> putJson(
|
Future<dynamic> putJson(String path, {Object? body, String? token}) async {
|
||||||
String path, {
|
final response = await _client.put(
|
||||||
Object? body,
|
Uri.parse('$baseUrl$path'),
|
||||||
String? token,
|
headers: _headers(token: token),
|
||||||
}) async {
|
body: body == null ? null : jsonEncode(body),
|
||||||
final response = await _client.put(
|
);
|
||||||
Uri.parse('$baseUrl$path'),
|
return _decodeOrNull(_guardResponse(response));
|
||||||
headers: _headers(token: token),
|
}
|
||||||
body: body == null ? null : jsonEncode(body),
|
|
||||||
);
|
|
||||||
return _decodeOrNull(_guardResponse(response));
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> patchJson(
|
Future<dynamic> patchJson(String path, {Object? body, String? token}) async {
|
||||||
String path, {
|
|
||||||
Object? body,
|
|
||||||
String? token,
|
|
||||||
}) async {
|
|
||||||
final response = await _client.patch(
|
final response = await _client.patch(
|
||||||
Uri.parse('$baseUrl$path'),
|
Uri.parse('$baseUrl$path'),
|
||||||
headers: _headers(token: token),
|
headers: _headers(token: token),
|
||||||
@@ -69,72 +57,75 @@ class ApiClient {
|
|||||||
);
|
);
|
||||||
return _decodeOrNull(_guardResponse(response));
|
return _decodeOrNull(_guardResponse(response));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final parsedBody = _decodeOrNull(response);
|
Future<dynamic> deleteJson(String path, {String? token}) async {
|
||||||
final serverMessage = _extractMessage(parsedBody);
|
final response = await _client.delete(
|
||||||
|
Uri.parse('$baseUrl$path'),
|
||||||
|
headers: _headers(token: token),
|
||||||
|
);
|
||||||
|
return _decodeOrNull(_guardResponse(response));
|
||||||
|
}
|
||||||
|
|
||||||
if (response.statusCode == 401) {
|
http.Response _guardResponse(http.Response response) {
|
||||||
throw ApiException(
|
if (response.statusCode >= 200 && response.statusCode < 300) {
|
||||||
type: ApiErrorType.unauthorized,
|
return response;
|
||||||
statusCode: 401,
|
|
||||||
message: serverMessage ?? 'Unauthorized',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.statusCode == 403) {
|
|
||||||
throw ApiException(
|
|
||||||
type: ApiErrorType.forbidden,
|
|
||||||
statusCode: 403,
|
|
||||||
message: serverMessage ?? 'Forbidden',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.statusCode >= 500) {
|
|
||||||
throw ApiException(
|
|
||||||
type: ApiErrorType.server,
|
|
||||||
statusCode: response.statusCode,
|
|
||||||
message: serverMessage ?? 'Server error',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw ApiException(
|
|
||||||
type: ApiErrorType.unknown,
|
|
||||||
statusCode: response.statusCode,
|
|
||||||
message: serverMessage ?? 'Request failed',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic _decodeOrNull(http.Response response) {
|
final parsedBody = _decodeOrNull(response);
|
||||||
final body = response.body.trim();
|
final serverMessage = _extractMessage(parsedBody);
|
||||||
if (body.isEmpty) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
if (response.statusCode == 401) {
|
||||||
return jsonDecode(body);
|
throw ApiException(
|
||||||
} catch (_) {
|
type: ApiErrorType.unauthorized,
|
||||||
return body;
|
statusCode: 401,
|
||||||
}
|
message: serverMessage ?? 'Unauthorized',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _extractMessage(dynamic parsedBody) {
|
if (response.statusCode == 403) {
|
||||||
if (parsedBody is Map<String, dynamic>) {
|
throw ApiException(
|
||||||
final message = parsedBody['message'];
|
type: ApiErrorType.forbidden,
|
||||||
if (message is String && message.trim().isNotEmpty) {
|
statusCode: 403,
|
||||||
return message;
|
message: serverMessage ?? 'Forbidden',
|
||||||
}
|
);
|
||||||
if (message is List && message.isNotEmpty) {
|
|
||||||
return message.first.toString();
|
|
||||||
}
|
|
||||||
final error = parsedBody['error'];
|
|
||||||
if (error is String && error.trim().isNotEmpty) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parsedBody is String && parsedBody.trim().isNotEmpty) {
|
|
||||||
return parsedBody;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.statusCode >= 500) {
|
||||||
|
throw ApiException(
|
||||||
|
type: ApiErrorType.server,
|
||||||
|
statusCode: response.statusCode,
|
||||||
|
message: serverMessage ?? 'Server error',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ApiException(
|
||||||
|
type: ApiErrorType.unknown,
|
||||||
|
statusCode: response.statusCode,
|
||||||
|
message: serverMessage ?? 'Request failed',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamic _decodeOrNull(http.Response response) {
|
||||||
|
final body = response.body.trim();
|
||||||
|
if (body.isEmpty) return null;
|
||||||
|
try {
|
||||||
|
return jsonDecode(body);
|
||||||
|
} catch (_) {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String? _extractMessage(dynamic parsedBody) {
|
||||||
|
if (parsedBody is Map<String, dynamic>) {
|
||||||
|
final message = parsedBody['message'];
|
||||||
|
if (message is String && message.trim().isNotEmpty) return message;
|
||||||
|
if (message is List && message.isNotEmpty) {
|
||||||
|
return message.first.toString();
|
||||||
|
}
|
||||||
|
final error = parsedBody['error'];
|
||||||
|
if (error is String && error.trim().isNotEmpty) return error;
|
||||||
|
}
|
||||||
|
if (parsedBody is String && parsedBody.trim().isNotEmpty) return parsedBody;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user