smart_api 1.0.4 copy "smart_api: ^1.0.4" to clipboard
smart_api: ^1.0.4 copied to clipboard

Dynamic Dio wrapper for Flutter — auto raw/multipart detection, global loader/snackbar/toast hooks, session-expiry handling, and no-internet retry, no try/catch boilerplate.

smart_api #

Your previous BaseClient + ApiProvider pattern worked, but required writing the same 15-line try/catch block for every new project. This package centralizes that logic once, making it fully reusable across all your projects.

Solves #

  • Raw vs. multipart confusion — Send a plain Map; if it contains a File or a valid local file path, the package automatically creates FormData and converts it to a MultipartFile. HTTP URL strings or plain text remain raw JSON. No manual conversions required.
  • Dynamic UI hooks (Loader / Snackbar / Toast) — Zero hard-coded UI packages (GetX, Fluttertoast, custom widgets, etc.). Set your handlers once inside SmartApiHooks, and every call uses them automatically. A built-in, dependency-free SmartApiToast is included if you don't want to reach for a third-party toast package at all.
  • Centrally handled status codes — 401/403 (session expired), timeouts, connection errors, and generic server errors are handled in one place instead of being rewritten across every API call.
  • No-internet retry flow — The onNoInternet(retry) hook receives a retry callback. Simply call retry() from your "No Internet" screen to re-fire the exact failed request.
  • One line per call — SmartApiClient.instance.post(...) — No ApiRequest, no RequestType, and no repetitive DataResponse.fromJson boilerplate.

Setup (once, in main.dart) #

import 'package:smart_api/smart_api.dart';

SmartApiConfig.init(
  baseUrl: "https://api.example.com",
  headerBuilder: () => {"Authorization": "Bearer $token"},
);

SmartApiHooks.showLoader = Utils.showLoading;
SmartApiHooks.hideLoader = Utils.hideLoading;
SmartApiHooks.showMessage = (msg, {type}) => Utils.showAlert(message: msg);
SmartApiHooks.onSessionExpired = () => Get.offAllNamed(AppRoutes.signIn);
SmartApiHooks.onNoInternet = (retry) => Get.to(() => NoInternetPage(onRetry: retry));

Call an API #

final res = await SmartApiClient.instance.post<UserModel>(
  "/api/login",
  body: {"email": email, "password": password},
  fromJson: (json) => UserModel.fromJson(json),
);

if (res.success) {
  // res.data is already typed as UserModel
} else {
  Utils.showAlert(message: res.message);
}

File upload — no separate handleMultipartRequest needed:

await SmartApiClient.instance.put("/api/editProfile", body: {
  "name": name,
  "image": pickedImage.path, // auto-detected and converted to multipart
});

See example/lib/main.dart for a full, runnable demo (GET/POST calls, no-internet retry, and session-expiry handling against a free test API).

Backend response shape differs per project? #

Two levels of control:

1. Just rename keys (most cases) — no custom parser required:

SmartApiConfig.init(
  baseUrl: "...",
  keyMap: const SmartApiKeyMap(
    successKeys: ['ok'],
    successValues: [true],
    messageKeys: ['msg'],
    dataKeys: ['payload'],
  ),
);

2. Fully custom shape (nested envelopes, etc.) — write a custom response parser:

SmartApiConfig.init(
  baseUrl: "...",
  responseParser: (json) => SmartApiEnvelope(
    success: json['meta']['ok'] == true,
    message: json['meta']['msg'] ?? '',
    data: json['payload'],
  ),
);

File uploads — auto or explicit, single or multiple, custom key names #

By default (autoDetectFiles: true), any File or valid local file path inside body is auto-converted to multipart. Disable it globally or per request to use explicit file bindings:

// Single image with a custom field name:
files: [SmartApiFile.single(key: "image", path: path)]

// Multiple images under the same field:
files: SmartApiFile.list(key: "images", paths: [p1, p2, p3])

// Different keys per file (e.g., front/back ID + selfie):
files: [
  SmartApiFile.single(key: "license_front", path: frontPath),
  SmartApiFile.single(key: "license_back", path: backPath),
  SmartApiFile.single(key: "profile_image", path: selfiePath),
]

Passing files always forces multipart mode, regardless of the autoDetectFiles setting. Standard text fields can still be passed in body alongside files.

Query params on any method, not just GET #

SmartApiClient.instance.post(
  "/api/roomSearch",
  body: data,                 // JSON or multipart body
  queryParams: {"id": roomId} // Appends ?id=... regardless of HTTP method
);

Built-in toast/snackbar — SmartApiToast #

No third-party toast package required. Sixteen-style-worth of look-and-feel is driven by one small config table instead of copy-pasted widgets, so picking a style is just an enum value:

SmartApiHooks.showMessage = (msg, {type}) => SmartApiToast.show(
  navigatorKey.currentContext!,
  msg,
  style: SmartApiToast.styleForMsgType(type), // or any SmartApiToastStyle directly
);

Available styles: info, success, error, warning, elite, gradient, timer, map, welcome, human, typewriter.

Future Roadmap Ideas #

  • Add retryCount to SmartApiRequest for automatic retries on 5xx responses.
  • Add response caching (per-endpoint TTL) for list and query endpoints.
  • Add a downloadFile() helper with progress callbacks using the same hook architecture.

smart_api_library #

smart_api_library #

smart_api_library #

9
likes
0
points
581
downloads

Publisher

unverified uploader

Weekly Downloads

Dynamic Dio wrapper for Flutter — auto raw/multipart detection, global loader/snackbar/toast hooks, session-expiry handling, and no-internet retry, no try/catch boilerplate.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, flutter

More

Packages that depend on smart_api