107 lines
3.0 KiB
Dart
107 lines
3.0 KiB
Dart
import 'dart:convert';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
typedef TokenProvider = String? Function();
|
|
typedef UnauthorizedHandler = Future<void> Function();
|
|
|
|
class ApiService {
|
|
final String baseUrl;
|
|
TokenProvider? _getToken;
|
|
UnauthorizedHandler? _onUnauthorized;
|
|
|
|
ApiService({required this.baseUrl});
|
|
|
|
void setTokenProvider(TokenProvider provider) {
|
|
_getToken = provider;
|
|
}
|
|
|
|
void setUnauthorizedHandler(UnauthorizedHandler handler) {
|
|
_onUnauthorized = handler;
|
|
}
|
|
|
|
Map<String, String> _buildHeaders(Map<String, String>? extra) {
|
|
final token = _getToken?.call();
|
|
final headers = {'accept': 'application/json', ...?extra};
|
|
if (token != null && token.isNotEmpty) {
|
|
headers['Authorization'] = 'Bearer $token';
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
Future<dynamic> get(String endpoint, {Map<String, String>? headers}) async {
|
|
final response = await http.get(
|
|
Uri.parse('$baseUrl$endpoint'),
|
|
headers: _buildHeaders(headers),
|
|
);
|
|
return _processResponse(response);
|
|
}
|
|
|
|
Future<dynamic> post(
|
|
String endpoint,
|
|
dynamic data, {
|
|
Map<String, String>? headers,
|
|
}) async {
|
|
final hasBody = data != null;
|
|
final response = await http.post(
|
|
Uri.parse('$baseUrl$endpoint'),
|
|
headers: _buildHeaders(hasBody ? _jsonHeaders(headers) : headers),
|
|
body: hasBody ? jsonEncode(data) : null,
|
|
);
|
|
return _processResponse(response);
|
|
}
|
|
|
|
Future<dynamic> postForm(String endpoint, Map<String, String> data) async {
|
|
final response = await http.post(
|
|
Uri.parse('$baseUrl$endpoint'),
|
|
headers: _buildHeaders({
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'accept': 'application/json',
|
|
}),
|
|
body: data, // http package handles form-encoding for Map<String, String>
|
|
);
|
|
return _processResponse(response);
|
|
}
|
|
|
|
Future<dynamic> put(
|
|
String endpoint,
|
|
dynamic data, {
|
|
Map<String, String>? headers,
|
|
}) async {
|
|
final hasBody = data != null;
|
|
final response = await http.put(
|
|
Uri.parse('$baseUrl$endpoint'),
|
|
headers: _buildHeaders(hasBody ? _jsonHeaders(headers) : headers),
|
|
body: hasBody ? jsonEncode(data) : null,
|
|
);
|
|
return _processResponse(response);
|
|
}
|
|
|
|
Future<dynamic> delete(
|
|
String endpoint, {
|
|
Map<String, String>? headers,
|
|
}) async {
|
|
final response = await http.delete(
|
|
Uri.parse('$baseUrl$endpoint'),
|
|
headers: _buildHeaders(headers),
|
|
);
|
|
return _processResponse(response);
|
|
}
|
|
|
|
Map<String, String> _jsonHeaders(Map<String, String>? extra) {
|
|
return {'Content-Type': 'application/json', if (extra != null) ...extra};
|
|
}
|
|
|
|
Future<dynamic> _processResponse(http.Response res) async {
|
|
final body = res.body.isNotEmpty ? jsonDecode(res.body) : null;
|
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
return body;
|
|
}
|
|
|
|
if (res.statusCode == 401 && _onUnauthorized != null) {
|
|
await _onUnauthorized!();
|
|
}
|
|
|
|
throw Exception('API error ${res.statusCode}: $body');
|
|
}
|
|
}
|