Networking
Einleitung
Nylo Website macht Networking einfach. Sie definieren API-Endpunkte in Service-Klassen, die NyApiService erweitern, und rufen sie dann von Ihren Seiten aus auf. Das Framework uebernimmt JSON-Dekodierung, Fehlerbehandlung, Caching und die automatische Konvertierung von Antworten in Ihre Model-Klassen (genannt "Morphing").
Ihre API-Services befinden sich in lib/app/networking/. Ein neues Projekt enthaelt einen Standard-ApiService:
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext})
: super(
buildContext,
decoders: modelDecoders,
);
@override
String get baseUrl => getEnv('API_BASE_URL');
@override
Map<Type, Interceptor> get interceptors => {
...super.interceptors,
};
Future fetchUsers() async {
return await network(
request: (request) => request.get("/users"),
);
}
}
Es gibt drei Moeglichkeiten, HTTP-Anfragen zu stellen:
| Ansatz | Rueckgabe | Am besten geeignet fuer |
|---|---|---|
Komfortmethoden (get, post, etc.) |
T? |
Einfache CRUD-Operationen |
network() |
T? |
Anfragen, die Caching, Wiederholungen oder benutzerdefinierte Header benoetigen |
networkResponse() |
NyResponse<T> |
Wenn Sie Statuscodes, Header oder Fehlerdetails benoetigen |
Unter der Haube verwendet Nylo Website Dio, einen leistungsstarken HTTP-Client.
Komfortmethoden
NyApiService bietet Kurzschreibmethoden fuer gaengige HTTP-Operationen. Diese rufen intern network() auf.
GET-Anfrage
Future<User?> fetchUser(int id) async {
return await get<User>(
"/users/$id",
queryParameters: {"include": "profile"},
);
}
POST-Anfrage
Future<User?> createUser(Map<String, dynamic> data) async {
return await post<User>("/users", data: data);
}
PUT-Anfrage
Future<User?> updateUser(int id, Map<String, dynamic> data) async {
return await put<User>("/users/$id", data: data);
}
DELETE-Anfrage
Future<bool?> deleteUser(int id) async {
return await delete<bool>("/users/$id");
}
PATCH-Anfrage
Future<User?> patchUser(int id, Map<String, dynamic> data) async {
return await patch<User>("/users/$id", data: data);
}
HEAD-Anfrage
Verwenden Sie HEAD, um die Existenz einer Ressource zu pruefen oder Header zu erhalten, ohne den Body herunterzuladen:
Future<bool> checkResourceExists(String url) async {
Response response = await head(url);
return response.statusCode == 200;
}
Network-Helfer
Die network-Methode gibt Ihnen mehr Kontrolle als die Komfortmethoden. Sie gibt die umgewandelten Daten (T?) direkt zurueck.
class ApiService extends NyApiService {
...
Future<User?> fetchUser(int id) async {
return await network<User>(
request: (request) => request.get("/users/$id"),
);
}
Future<List<User>?> fetchUsers() async {
return await network<List<User>>(
request: (request) => request.get("/users"),
);
}
Future<User?> createUser(Map<String, dynamic> data) async {
return await network<User>(
request: (request) => request.post("/users", data: data),
);
}
}
Der request-Callback erhaelt eine Dio-Instanz mit Ihrer Basis-URL und Interceptors bereits konfiguriert.
network-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
request |
Function(Dio) |
Die auszufuehrende HTTP-Anfrage (erforderlich) |
bearerToken |
String? |
Bearer-Token fuer diese Anfrage |
baseUrl |
String? |
Basis-URL des Services ueberschreiben |
headers |
Map<String, dynamic>? |
Zusaetzliche Header |
retry |
int? |
Anzahl der Wiederholungsversuche |
retryDelay |
Duration? |
Verzoegerung zwischen Wiederholungen |
retryIf |
bool Function(DioException)? |
Bedingung fuer Wiederholung |
connectionTimeout |
Duration? |
Verbindungs-Timeout |
receiveTimeout |
Duration? |
Empfangs-Timeout |
sendTimeout |
Duration? |
Sende-Timeout |
cacheKey |
String? |
Cache-Schluessel |
cacheDuration |
Duration? |
Cache-Dauer |
cachePolicy |
CachePolicy? |
Cache-Strategie |
checkConnectivity |
bool? |
Konnektivitaet vor Anfrage pruefen |
handleSuccess |
Function(NyResponse<T>)? |
Erfolgs-Callback |
handleFailure |
Function(NyResponse<T>)? |
Fehler-Callback |
networkResponse-Helfer
Verwenden Sie networkResponse, wenn Sie Zugriff auf die vollstaendige Antwort benoetigen -- Statuscodes, Header, Fehlermeldungen -- nicht nur die Daten. Es gibt ein NyResponse<T> anstelle von T? zurueck.
Verwenden Sie networkResponse, wenn Sie:
- HTTP-Statuscodes fuer spezifische Behandlung pruefen muessen
- Auf Antwort-Header zugreifen muessen
- Detaillierte Fehlermeldungen fuer Benutzer-Feedback benoetigen
- Benutzerdefinierte Fehlerbehandlungslogik implementieren muessen
Future<NyResponse<User>> fetchUser(int id) async {
return await networkResponse<User>(
request: (request) => request.get("/users/$id"),
);
}
Verwenden Sie dann die Antwort in Ihrer Seite:
NyResponse<User> response = await _apiService.fetchUser(1);
if (response.isSuccessful) {
User? user = response.data;
print('Status: ${response.statusCode}');
} else {
print('Error: ${response.errorMessage}');
print('Status: ${response.statusCode}');
}
network vs networkResponse
// network() — returns the data directly
User? user = await network<User>(
request: (request) => request.get("/users/1"),
);
// networkResponse() — returns the full response
NyResponse<User> response = await networkResponse<User>(
request: (request) => request.get("/users/1"),
);
User? user = response.data;
int? status = response.statusCode;
Beide Methoden akzeptieren die gleichen Parameter. Waehlen Sie networkResponse, wenn Sie die Antwort ueber die reinen Daten hinaus inspizieren muessen.
NyResponse
NyResponse<T> umhuellt die Dio-Antwort mit umgewandelten Daten und Status-Helfern.
Eigenschaften
| Eigenschaft | Typ | Beschreibung |
|---|---|---|
response |
Response? |
Originale Dio-Antwort |
data |
T? |
Umgewandelte/dekodierte Daten |
rawData |
dynamic |
Rohe Antwortdaten |
headers |
Headers? |
Antwort-Header |
statusCode |
int? |
HTTP-Statuscode |
statusMessage |
String? |
HTTP-Statusnachricht |
contentType |
String? |
Content-Type aus den Headern |
errorMessage |
String? |
Extrahierte Fehlermeldung |
Status-Pruefungen
| Getter | Beschreibung |
|---|---|
isSuccessful |
Status 200-299 |
isClientError |
Status 400-499 |
isServerError |
Status 500-599 |
isRedirect |
Status 300-399 |
hasData |
Daten sind nicht null |
isUnauthorized |
Status 401 |
isForbidden |
Status 403 |
isNotFound |
Status 404 |
isTimeout |
Status 408 |
isConflict |
Status 409 |
isRateLimited |
Status 429 |
Daten-Helfer
NyResponse<User> response = await apiService.fetchUser(1);
// Get data or throw if null
User user = response.dataOrThrow('User not found');
// Get data or use a fallback
User user = response.dataOr(User.guest());
// Run callback only if successful
String? greeting = response.ifSuccessful((user) => 'Hello ${user.name}');
// Pattern match on success/failure
String result = response.when(
success: (user) => 'Welcome, ${user.name}!',
failure: (response) => 'Error: ${response.statusMessage}',
);
// Get a specific header
String? authHeader = response.getHeader('Authorization');
Basis-Optionen
Konfigurieren Sie Standard-Dio-Optionen fuer Ihren API-Service mit dem baseOptions-Parameter:
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(
buildContext,
decoders: modelDecoders,
baseOptions: (BaseOptions baseOptions) {
return baseOptions
..connectTimeout = Duration(seconds: 5)
..sendTimeout = Duration(seconds: 5)
..receiveTimeout = Duration(seconds: 5);
},
);
...
}
Sie koennen Optionen auch dynamisch auf einer Instanz konfigurieren:
apiService.setConnectTimeout(Duration(seconds: 10));
apiService.setReceiveTimeout(Duration(seconds: 30));
apiService.setSendTimeout(Duration(seconds: 10));
apiService.setContentType('application/json');
Klicken Sie hier, um alle Basis-Optionen zu sehen, die Sie festlegen koennen.
Header hinzufuegen
Header pro Anfrage
Future fetchWithHeaders() async => await network(
request: (request) => request.get("/test"),
headers: {
"Authorization": "Bearer aToken123",
"Device": "iPhone"
}
);
Bearer-Token
Future fetchUser() async => await network(
request: (request) => request.get("/user"),
bearerToken: "hello-world-123",
);
Service-Level-Header
apiService.setHeaders({"X-Custom-Header": "value"});
apiService.setBearerToken("my-token");
RequestHeaders-Extension
Der RequestHeaders-Typ (ein Map<String, dynamic> Typedef) bietet Hilfsmethoden:
@override
Future<RequestHeaders> setAuthHeaders(RequestHeaders headers) async {
String? token = Auth.data(field: 'token');
if (token != null) {
headers.addBearerToken(token);
}
headers.addHeader('X-App-Version', '1.0.0');
return headers;
}
| Methode | Beschreibung |
|---|---|
addBearerToken(token) |
Den Authorization: Bearer-Header setzen |
getBearerToken() |
Das Bearer-Token aus den Headern lesen |
addHeader(key, value) |
Einen benutzerdefinierten Header hinzufuegen |
hasHeader(key) |
Pruefen, ob ein Header existiert |
Dateien hochladen
Einzeldatei-Upload
Future<UploadResponse?> uploadAvatar(String filePath) async {
return await upload<UploadResponse>(
'/upload',
filePath: filePath,
fieldName: 'avatar',
additionalFields: {'userId': '123'},
onProgress: (sent, total) {
double progress = sent / total * 100;
print('Progress: ${progress.toStringAsFixed(0)}%');
},
);
}
Mehrdatei-Upload
Future<UploadResponse?> uploadDocuments() async {
return await uploadMultiple<UploadResponse>(
'/upload',
files: {
'avatar': '/path/to/avatar.jpg',
'document': '/path/to/doc.pdf',
},
additionalFields: {'userId': '123'},
onProgress: (sent, total) {
print('Progress: ${(sent / total * 100).toStringAsFixed(0)}%');
},
);
}
Dateien herunterladen
Future<void> downloadFile(String url, String savePath) async {
await download(
url,
savePath: savePath,
onProgress: (received, total) {
if (total != -1) {
print('Progress: ${(received / total * 100).toStringAsFixed(0)}%');
}
},
deleteOnError: true,
);
}
Interceptors
Interceptors ermoeglichen es Ihnen, Anfragen vor dem Senden zu modifizieren, Antworten zu verarbeiten und Fehler zu behandeln. Sie werden bei jeder Anfrage ausgefuehrt, die ueber den API-Service gemacht wird.
Verwenden Sie Interceptors, wenn Sie:
- Authentifizierungs-Header zu allen Anfragen hinzufuegen muessen
- Anfragen und Antworten fuer das Debugging loggen muessen
- Anfrage-/Antwortdaten global transformieren muessen
- Bestimmte Fehlercodes behandeln muessen (z.B. Tokens bei 401 erneuern)
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(buildContext, decoders: modelDecoders);
@override
Map<Type, Interceptor> get interceptors => {
...super.interceptors,
BearerAuthInterceptor: BearerAuthInterceptor(),
LoggingInterceptor: LoggingInterceptor(),
};
...
}
Einen benutzerdefinierten Interceptor erstellen
metro make:interceptor logging
Datei: app/networking/dio/interceptors/logging_interceptor.dart
import 'package:nylo_framework/nylo_framework.dart';
class LoggingInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('REQUEST[${options.method}] => PATH: ${options.path}');
return super.onRequest(options, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('RESPONSE[${response.statusCode}] => PATH: ${response.requestOptions.path}');
handler.next(response);
}
@override
void onError(DioException dioException, ErrorInterceptorHandler handler) {
print('ERROR[${dioException.response?.statusCode}] => PATH: ${dioException.requestOptions.path}');
handler.next(dioException);
}
}
Network Logger
Nylo Website enthaelt einen eingebauten NetworkLogger-Interceptor. Er ist standardmaessig aktiviert, wenn APP_DEBUG in Ihrer Umgebung auf true gesetzt ist.
Konfiguration
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(
buildContext,
decoders: modelDecoders,
useNetworkLogger: true,
networkLogger: NetworkLogger(
logLevel: LogLevelType.verbose,
request: true,
requestHeader: true,
requestBody: true,
responseBody: true,
responseHeader: false,
error: true,
),
);
}
Sie koennen ihn deaktivieren, indem Sie useNetworkLogger: false setzen.
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext})
: super(
buildContext,
decoders: modelDecoders,
useNetworkLogger: false, // <-- Logger deaktivieren
);
Log-Level
| Level | Beschreibung |
|---|---|
LogLevelType.verbose |
Alle Anfrage-/Antwortdetails ausgeben |
LogLevelType.minimal |
Nur Methode, URL, Status und Zeit ausgeben |
LogLevelType.none |
Keine Logging-Ausgabe |
Logs filtern
NetworkLogger(
filter: (options, args) {
// Only log requests to specific endpoints
return options.path.contains('/api/v1');
},
)
Einen API-Service verwenden
Es gibt zwei Moeglichkeiten, Ihren API-Service von einer Seite aus aufzurufen.
Direkte Instanziierung
class _MyHomePageState extends NyPage<MyHomePage> {
ApiService _apiService = ApiService();
@override
get init => () async {
List<User>? users = await _apiService.fetchUsers();
print(users);
};
}
Den api()-Helfer verwenden
Der api-Helfer erstellt Instanzen unter Verwendung Ihrer apiDecoders aus config/decoders.dart:
class _MyHomePageState extends NyPage<MyHomePage> {
@override
get init => () async {
User? user = await api<ApiService>((request) => request.fetchUser());
print(user);
};
}
Mit Callbacks:
await api<ApiService>(
(request) => request.fetchUser(),
onSuccess: (response, data) {
// data is the morphed User? instance
},
onError: (DioException dioException) {
// Handle the error
},
);
api()-Helfer-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
request |
Function(T) |
Die API-Anfragefunktion |
context |
BuildContext? |
Build-Kontext |
headers |
Map<String, dynamic> |
Zusaetzliche Header |
bearerToken |
String? |
Bearer-Token |
baseUrl |
String? |
Basis-URL ueberschreiben |
page |
int? |
Paginierungsseite |
perPage |
int? |
Elemente pro Seite |
retry |
int |
Wiederholungsversuche |
retryDelay |
Duration? |
Verzoegerung zwischen Wiederholungen |
onSuccess |
Function(Response, dynamic)? |
Erfolgs-Callback |
onError |
Function(DioException)? |
Fehler-Callback |
cacheKey |
String? |
Cache-Schluessel |
cacheDuration |
Duration? |
Cache-Dauer |
Einen API-Service erstellen
Um einen neuen API-Service zu erstellen:
metro make:api_service user
Mit einem Model:
metro make:api_service user --model="User"
Dies erstellt einen API-Service mit CRUD-Methoden:
class UserApiService extends NyApiService {
...
Future<List<User>?> fetchAll({dynamic query}) async {
return await network<List<User>>(
request: (request) => request.get("/endpoint-path", queryParameters: query),
);
}
Future<User?> find({required int id}) async {
return await network<User>(
request: (request) => request.get("/endpoint-path/$id"),
);
}
Future<User?> create({required dynamic data}) async {
return await network<User>(
request: (request) => request.post("/endpoint-path", data: data),
);
}
Future<User?> update({dynamic query}) async {
return await network<User>(
request: (request) => request.put("/endpoint-path", queryParameters: query),
);
}
Future<bool?> delete({required int id}) async {
return await network<bool>(
request: (request) => request.delete("/endpoint-path/$id"),
);
}
}
JSON in Models umwandeln
"Morphing" ist der Begriff von Nylo Website fuer die automatische Konvertierung von JSON-Antworten in Ihre Dart-Model-Klassen. Wenn Sie network<User>(...) verwenden, wird das JSON der Antwort durch Ihren Decoder geleitet, um eine User-Instanz zu erstellen -- kein manuelles Parsen noetig.
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(buildContext, decoders: modelDecoders);
// Returns a single User
Future<User?> fetchUser() async {
return await network<User>(
request: (request) => request.get("/user/1"),
);
}
// Returns a List of Users
Future<List<User>?> fetchUsers() async {
return await network<List<User>>(
request: (request) => request.get("/users"),
);
}
}
Die Decoder werden in lib/bootstrap/decoders.dart definiert:
final Map<Type, dynamic> modelDecoders = {
User: (data) => User.fromJson(data),
List<User>: (data) =>
List.from(data).map((json) => User.fromJson(json)).toList(),
};
Der Typparameter, den Sie an network<T>() uebergeben, wird mit Ihrer modelDecoders-Map abgeglichen, um den richtigen Decoder zu finden.
Siehe auch: Decoders fuer Details zur Registrierung von Model-Decodern.
Antworten cachen
Cachen Sie Antworten, um API-Aufrufe zu reduzieren und die Leistung zu verbessern. Caching ist nuetzlich fuer Daten, die sich nicht haeufig aendern, wie Laenderlisten, Kategorien oder Konfigurationen.
Geben Sie einen cacheKey und optional eine cacheDuration an:
Future<List<Country>> fetchCountries() async {
return await network<List<Country>>(
request: (request) => request.get("/countries"),
cacheKey: "app_countries",
cacheDuration: const Duration(hours: 1),
) ?? [];
}
Cache leeren
// Clear a specific cache key
await apiService.clearCache("app_countries");
// Clear all API cache
await apiService.clearAllCache();
Caching mit dem api()-Helfer
api<ApiService>(
(request) => request.fetchCountries(),
cacheKey: "app_countries",
cacheDuration: const Duration(hours: 1),
);
Cache-Richtlinien
Verwenden Sie CachePolicy fuer feinkoernige Kontrolle ueber das Caching-Verhalten:
| Richtlinie | Beschreibung |
|---|---|
CachePolicy.networkOnly |
Immer vom Netzwerk abrufen (Standard) |
CachePolicy.cacheFirst |
Zuerst Cache versuchen, bei Fehlen Netzwerk verwenden |
CachePolicy.networkFirst |
Zuerst Netzwerk versuchen, bei Fehler Cache verwenden |
CachePolicy.cacheOnly |
Nur Cache verwenden, Fehler wenn leer |
CachePolicy.staleWhileRevalidate |
Cache sofort zurueckgeben, im Hintergrund aktualisieren |
Verwendung
Future<List<Country>> fetchCountries() async {
return await network<List<Country>>(
request: (request) => request.get("/countries"),
cacheKey: "app_countries",
cacheDuration: const Duration(hours: 1),
cachePolicy: CachePolicy.staleWhileRevalidate,
) ?? [];
}
Wann welche Richtlinie verwenden
- cacheFirst -- Daten, die sich selten aendern. Gibt gecachte Daten sofort zurueck, ruft nur vom Netzwerk ab, wenn der Cache leer ist.
- networkFirst -- Daten, die moeglichst aktuell sein sollten. Versucht zuerst das Netzwerk, faellt bei Fehler auf Cache zurueck.
- staleWhileRevalidate -- UI, die eine sofortige Antwort benoetigt, aber aktuell bleiben sollte. Gibt gecachte Daten zurueck und aktualisiert dann im Hintergrund.
- cacheOnly -- Offline-Modus. Wirft einen Fehler, wenn keine gecachten Daten vorhanden sind.
Hinweis: Wenn Sie einen
cacheKeyoder einecacheDurationohne Angabe einercachePolicyangeben, ist die StandardrichtliniecacheFirst.
Fehlgeschlagene Anfragen wiederholen
Wiederholen Sie automatisch fehlgeschlagene Anfragen.
Einfache Wiederholung
Future fetchUsers() async {
return await network(
request: (request) => request.get("/users"),
retry: 3,
);
}
Wiederholung mit Verzoegerung
Future fetchUsers() async {
return await network(
request: (request) => request.get("/users"),
retry: 3,
retryDelay: Duration(seconds: 2),
);
}
Bedingte Wiederholung
Future fetchUsers() async {
return await network(
request: (request) => request.get("/users"),
retry: 3,
retryIf: (DioException dioException) {
// Only retry on server errors
return dioException.response?.statusCode == 500;
},
);
}
Service-Level-Wiederholung
apiService.setRetry(3);
apiService.setRetryDelay(Duration(seconds: 2));
apiService.setRetryIf((dioException) => dioException.response?.statusCode == 500);
Konnektivitaetspruefungen
Schnell fehlschlagen, wenn das Geraet offline ist, anstatt auf ein Timeout zu warten.
Service-Level
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(buildContext, decoders: modelDecoders);
@override
bool get checkConnectivityBeforeRequest => true;
...
}
Pro Anfrage
await network(
request: (request) => request.get("/users"),
checkConnectivity: true,
);
Dynamisch
apiService.setCheckConnectivityBeforeRequest(true);
Wenn aktiviert und das Geraet offline ist:
networkFirst-Richtlinie faellt auf Cache zurueck- Andere Richtlinien werfen sofort
DioExceptionType.connectionError
Cancel Tokens
Verwalten und stornieren Sie ausstehende Anfragen.
// Create a managed cancel token
final token = apiService.createCancelToken();
await apiService.get('/endpoint', cancelToken: token);
// Cancel all pending requests (e.g., on logout)
apiService.cancelAllRequests('User logged out');
// Check active request count
int count = apiService.activeRequestCount;
// Clean up a specific token when done
apiService.removeCancelToken(token);
Auth-Header setzen
Ueberschreiben Sie setAuthHeaders, um Authentifizierungs-Header an jede Anfrage anzuhaengen. Diese Methode wird vor jeder Anfrage aufgerufen, wenn shouldSetAuthHeaders auf true steht (Standard).
class ApiService extends NyApiService {
...
@override
Future<RequestHeaders> setAuthHeaders(RequestHeaders headers) async {
String? myAuthToken = Auth.data(field: 'token');
if (myAuthToken != null) {
headers.addBearerToken(myAuthToken);
}
return headers;
}
}
Auth-Header deaktivieren
Fuer oeffentliche Endpunkte, die keine Authentifizierung benoetigen:
// Per-request
await network(
request: (request) => request.get("/public-endpoint"),
shouldSetAuthHeaders: false,
);
// Service-level
apiService.setShouldSetAuthHeaders(false);
Siehe auch: Authentifizierung fuer Details zur Benutzerauthentifizierung und Token-Speicherung.
Tokens aktualisieren
Ueberschreiben Sie shouldRefreshToken und refreshToken, um den Token-Ablauf zu behandeln. Diese werden vor jeder Anfrage aufgerufen.
class ApiService extends NyApiService {
...
@override
Future<bool> shouldRefreshToken() async {
// Check if the token needs refreshing
return false;
}
@override
Future<void> refreshToken(Dio dio) async {
// Use the fresh Dio instance (no interceptors) to refresh the token
dynamic response = (await dio.post("https://example.com/refresh-token")).data;
// Save the new token to storage
await Auth.set((data) {
data['token'] = response['token'];
return data;
});
}
}
Der dio-Parameter in refreshToken ist eine neue Dio-Instanz, getrennt von der Hauptinstanz des Services, um Interceptor-Schleifen zu vermeiden.
Singleton API-Service
Standardmaessig erstellt der api-Helfer jedes Mal eine neue Instanz. Um ein Singleton zu verwenden, uebergeben Sie eine Instanz anstelle einer Factory in config/decoders.dart:
final Map<Type, dynamic> apiDecoders = {
ApiService: () => ApiService(), // New instance each time
ApiService: ApiService(), // Singleton — same instance always
};
Erweiterte Konfiguration
Benutzerdefinierte Dio-Initialisierung
class ApiService extends NyApiService {
ApiService({BuildContext? buildContext}) : super(
buildContext,
decoders: modelDecoders,
initDio: (Dio dio) {
dio.options.validateStatus = (status) => status! < 500;
return dio;
},
);
}
Zugriff auf die Dio-Instanz
Dio dioInstance = apiService.dio;
Response response = await dioInstance.request(
'/custom-endpoint',
options: Options(method: 'OPTIONS'),
);
Paginierungs-Helfer
apiService.setPagination(
1,
paramPage: 'page',
paramPerPage: 'per_page',
perPage: '20',
);
Event-Callbacks
apiService.onSuccess((response, data) {
print('Success: ${response.statusCode}');
});
apiService.onError((dioException) {
print('Error: ${dioException.message}');
});
Ueberschreibbare Eigenschaften
| Eigenschaft | Typ | Standard | Beschreibung |
|---|---|---|---|
baseUrl |
String |
"" |
Basis-URL fuer alle Anfragen |
interceptors |
Map<Type, Interceptor> |
{} |
Dio-Interceptors |
decoders |
Map<Type, dynamic>? |
{} |
Model-Decoder fuer JSON-Umwandlung |
shouldSetAuthHeaders |
bool |
true |
Ob setAuthHeaders vor Anfragen aufgerufen werden soll |
retry |
int |
0 |
Standard-Wiederholungsversuche |
retryDelay |
Duration |
1 second |
Standard-Verzoegerung zwischen Wiederholungen |
checkConnectivityBeforeRequest |
bool |
false |
Konnektivitaet vor Anfragen pruefen |