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

Dynamic Dio wrapper for Flutter — auto raw/multipart detection, global loader/snackbar hooks, configurable session-expiry & error handling, no-internet retry, and one-line API calls (no repeated try/c [...]

smart_api[cite: 1] #

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

Solves[cite: 1] #

  • 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[cite: 1]. HTTP URL strings or plain text remain raw JSON[cite: 1]. No manual conversions required[cite: 1].
  • Dynamic UI hooks (Loader / Snackbar / Toast) — Zero hard-coded UI packages (GetX, Fluttertoast, custom widgets, etc.)[cite: 1]. Set your handlers once inside SmartApiHooks, and every call uses them automatically[cite: 1].
  • 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[cite: 1].
  • No-internet retry flow — The onNoInternet(retry) hook receives a retry callback[cite: 1]. Simply call retry() from your "No Internet" screen to re-fire the exact failed request[cite: 1].
  • One line per call — SmartApiClient.instance.post(...) — No ApiRequest, no RequestType, and no repetitive DataResponse.fromJson boilerplate[cite: 1].

Setup (once, in main.dart)[cite: 1] #

SmartApiConfig.init(
  baseUrl: "[https://api.example.com](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));
```[cite: 1]

## Call an API[cite: 1]

```dart
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);
}
```[cite: 1]

File upload — no separate `handleMultipartRequest` needed[cite: 1]:

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

See `example/usage_example.dart` for a full before/after comparison with your existing `signupApi` / `editProfile` flow[cite: 1].

## Backend response shape differs per project?[cite: 1]

Two levels of control[cite: 1]:

**1. Just rename keys (most cases)** — no custom parser required[cite: 1]:

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

**2. Fully custom shape** (nested envelopes, etc.) — write a custom response parser[cite: 1]:

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

## File uploads — auto or explicit, single or multiple, custom key names[cite: 1]

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

```dart
// 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),
]
```[cite: 1]

Passing `files` always forces multipart mode, regardless of the `autoDetectFiles` setting[cite: 1]. Standard text fields can still be passed in `body` alongside files[cite: 1].

## Query params on any method, not just GET[cite: 1]

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

## Future Roadmap Ideas[cite: 1]

- Add `retryCount` to `SmartApiRequest` for automatic retries on 5xx responses[cite: 1].
- Add response caching (per-endpoint TTL) for list and query endpoints[cite: 1].
- Add a `downloadFile()` helper with progress callbacks using the same hook architecture[cite: 1].
9
likes
0
points
581
downloads

Publisher

unverified uploader

Weekly Downloads

Dynamic Dio wrapper for Flutter — auto raw/multipart detection, global loader/snackbar hooks, configurable session-expiry & error handling, no-internet retry, and one-line API calls (no repeated try/catch boilerplate).

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, flutter

More

Packages that depend on smart_api