Aus öffentlichen Paketdaten erstellte Orientierung.
Ein Flutter/Dart-Paket, das eine saubere Abstraktion für die Interaktion mit REST-APIs bereitstellt. Es vereinfacht HTTP-Anfragen und behandelt häufige Herausforderungen wie Fehlermanagement und JWT-Authentifizierung mit automatischer Refresh-Token-Unterstützung. Entwickelt, um die API-Kommunikation über mehrere Plattformen zu vereinfachen, reduziert es Boilerplate-Code und erhöht die Zuverlässigkeit bei Netzwerkoperationen. Ideal für Anwendungen, die sichere, konsistente Backend-Integration erfordern.
Anwendungsfälle
Integration mit authentifizierten REST-APIs
HTTP-Fehler elegant behandeln
Automatisierung der JWT-Token-Aktualisierung
Skalierbare Backend-Integrationen erstellen
Verwaltung des Lebenszyklus der API-Anfrage
Unterstützung von plattformübergreifenden Netzwerkaufrufen
Entwickler, die weniger Netzwerk-Boilerplate suchen
Teams, die Multiplattform-Anwendungen erstellen
Apps mit JWT-basierter Authentifizierung
Hinweise
Erforderliche korrekte JWT-Token-Einrichtung
Abhängig von externem http-Paket
Benutzerdefinierte Fehlerzuordnung kann erforderlich sein
Beschränkt auf REST-artige Endpunkte
Nicht geeignet für nicht-HTTP-Protokolle
Der Authentifizierungsablauf muss mit der Serverlogik übereinstimmen
Original-README
Originaler README-Schnappschuss aus dem verknüpften Quell-Repository. Aktuelle Inhalte finden Sie im Repository.
Rest API Client
A production-ready HTTP client for Flutter applications that simplifies REST API communication with built-in support for JWT authentication, automatic token refresh, response caching, retry logic, and comprehensive error handling.
Features
JWT Authentication - Automatic token management with secure storage (Keychain/EncryptedSharedPreferences)
Token Refresh - Two strategies: response-and-retry or preemptive refresh before expiry
Response Caching - Intelligent caching with configurable expiration
Retry Logic - Exponential backoff for failed requests
// GET requestfinal result = await client.get('/users');
// GET with query parametersfinal result = await client.get('/users', queryParameters: {'page': 1, 'limit': 10});
// POST requestfinal result = await client.post('/users', data: {'name': 'John', 'email': 'john@example.com'});
// PUT requestfinal result = await client.put('/users/1', data: {'name': 'John Updated'});
// PATCH requestfinal result = await client.patch('/users/1', data: {'name': 'John Patched'});
// DELETE requestfinal result = await client.delete('/users/1');
// HEAD requestfinal result = await client.head('/users/1');
With Type Conversion
Use onSuccess to parse responses into typed objects:
final result = await client.get<User>(
'/users/1',
onSuccess: (data) => User.fromJson(data),
);
if (result.hasData) {
User user = result.data!;
print(user.name);
}
Per-Request Options
final result = await client.get(
'/users',
options: RestApiClientRequestOptions(
headers: {'X-Custom': 'value'},
contentType: 'application/json',
requiresAuth: false, // Skip authentication for this request
silentException: true, // Don't broadcast exceptions
),
);
Caching Strategies
Cache-First (Stale-While-Revalidate)
Returns cached data immediately, then fetches fresh data:
awaitfor (final result in client.getStreamed('/users')) {
if (result.hasData) {
// First emission: cached data (if available)// Second emission: fresh network dataupdateUI(result.data);
}
}
Cache-Only
Get data from cache only (no network request):
final result = await client.getCached('/users');
if (result.hasData) {
print('Cached data: ${result.data}');
}
Cache-Or-Network
Try cache first, fall back to network:
final result = await client.getCachedOrNetwork('/users');
Custom Cache Duration
final result = await client.get(
'/users',
cacheLifetimeDuration: Duration(hours: 1),
);
Authentication
Login Flow
// 1. Make login requestfinal loginResult = await client.post('/auth/login', data: {
'email': 'user@example.com',
'password': 'password123',
});
// 2. Authorize the client with received tokensif (loginResult.hasData) {
await client.authorize(
jwt: loginResult.data['accessToken'],
refreshToken: loginResult.data['refreshToken'],
);
}
// 3. All subsequent requests will include the JWTfinal userResult = await client.get('/users/me');
Check Authorization Status
final isLoggedIn = await client.isAuthorized();
Logout
await client.unAuthorize();
await client.clearStorage(); // Clear tokens and cached data
Error Handling
Result Object
All requests return a Result<T> object:
final result = await client.get('/users');
// Check for dataif (result.hasData) {
print(result.data);
}
// Check for errorsif (result.isError) {
print(result.exception);
}
// Check specific error typesif (result.isConnectionError) {
print('No internet connection');
}
// Access HTTP statusprint(result.statusCode); // e.g., 200, 404, 500print(result.statusMessage); // e.g., "OK", "Not Found"
Exception Types
Exception
HTTP Status
Description
ValidationException
400, 404, 422
Input validation errors
UnauthorizedException
401
Authentication required
ForbiddenException
403
Access denied
ServerErrorException
500, 502
Server-side errors
NetworkErrorException
-
Connection issues
Global Exception Stream
Listen to all exceptions across the app:
client.exceptionHandler.exceptions.stream.listen((exception) {
if (exception isUnauthorizedException) {
// Redirect to login
navigatorKey.currentState?.pushReplacementNamed('/login');
} elseif (exception isNetworkErrorException) {
// Show offline bannershowSnackBar('No internet connection');
}
});
Suppress Exceptions
// Suppress for a single requestfinal result = await client.get(
'/users',
options: RestApiClientRequestOptions(silentException: true),
);
File Downloads
final result = await client.download(
'/files/document.pdf',
'/path/to/save/document.pdf',
onReceiveProgress: (received, total) {
final progress = (received / total * 100).toStringAsFixed(0);
print('Download progress: $progress%');
},
);
Headers
// Set content type
client.setContentType('application/json');
// Set language
client.setAcceptLanguageHeader('en');
// Add custom header
client.addOrUpdateHeader(key: 'X-Api-Key', value: 'your-api-key');
// Access current headersprint(client.headers);