You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
2.2 KiB
Dart
71 lines
2.2 KiB
Dart
import 'dart:convert';
|
|
import 'package:http/http.dart' as http;
|
|
|
|
class ApiClient {
|
|
ApiClient(
|
|
this.baseUrl, {
|
|
this.getAccessToken,
|
|
this.onUnauthorized,
|
|
});
|
|
|
|
final String baseUrl; // z.B. https://api.windesign.at/hedgehogs.php?r=
|
|
final Future<String?> Function()? getAccessToken;
|
|
final Future<void> Function()? onUnauthorized;
|
|
|
|
Future<http.Response> _send(String method, String path,
|
|
{Object? body}) async {
|
|
final uri = Uri.parse('$baseUrl$path');
|
|
final headers = {'Content-Type': 'application/json'};
|
|
final token = await getAccessToken?.call();
|
|
if (token != null) headers['Authorization'] = 'Bearer $token';
|
|
|
|
switch (method) {
|
|
case 'GET':
|
|
return http.get(uri, headers: headers);
|
|
case 'POST':
|
|
return http.post(uri,
|
|
headers: headers, body: body == null ? null : jsonEncode(body));
|
|
case 'PUT':
|
|
return http.put(uri,
|
|
headers: headers, body: body == null ? null : jsonEncode(body));
|
|
case 'DELETE':
|
|
return http.delete(uri, headers: headers);
|
|
default:
|
|
throw UnimplementedError(method);
|
|
}
|
|
}
|
|
|
|
Future<T> _requestWithRetry<T>(String method, String path,
|
|
{Object? body}) async {
|
|
var res = await _send(method, path, body: body);
|
|
|
|
if (res.statusCode == 401 && onUnauthorized != null) {
|
|
await onUnauthorized!.call();
|
|
res = await _send(method, path, body: body);
|
|
}
|
|
|
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
if (res.body.isEmpty) return (null as T);
|
|
final decoded = jsonDecode(res.body);
|
|
return decoded as T;
|
|
}
|
|
throw ApiException(res.statusCode, res.body);
|
|
}
|
|
|
|
Future<T> get<T>(String path) async => _requestWithRetry<T>('GET', path);
|
|
Future<T> post<T>(String path, Object body) async =>
|
|
_requestWithRetry<T>('POST', path, body: body);
|
|
Future<T> put<T>(String path, Object body) async =>
|
|
_requestWithRetry<T>('PUT', path, body: body);
|
|
Future<T> delete<T>(String path) async =>
|
|
_requestWithRetry<T>('DELETE', path);
|
|
}
|
|
|
|
class ApiException implements Exception {
|
|
final int status;
|
|
final String body;
|
|
ApiException(this.status, this.body);
|
|
@override
|
|
String toString() => 'ApiException($status): $body';
|
|
}
|