easy_api_provider 3.0.0
easy_api_provider: ^3.0.0 copied to clipboard
Flutter REST API client and API provider built on Dio: typed responses, retry, caching, deduplication, token refresh, pagination, and reactive UI widgets.
Changelog #
3.0.0 - 2026-08-22 #
Breaking Changes #
ApiResponseis now generic:ApiResponse<T>. Thedatafield changes fromdynamictoT?. Existing code usingApiResponsewithout a type parameter continues to work asApiResponse<dynamic>— no changes required for callers that do not use the newdecoderparam.- All HTTP methods (
get,post,put,patch,delete,upload,download) are now generic:Future<ApiResponse<T>>. Type inference means existing call sites need no changes.
Added #
decoderoptional parameter on all HTTP methods — pass a function to decode the raw response body into a strongly-typed object with zero casts:final ApiResponse<List<Post>> res = await ApiProvider.instance.get<List<Post>>( '/posts', decoder: (data) => (data['posts'] as List).map(Post.fromJson).toList(), );
Fixed #
- Non-exhaustive
DioExceptionTypeswitch statements inApiProvider._handleDioErrorandRetryInterceptor._shouldRetrythat failed static analysis after dio addedDioExceptionType.transformTimeout. Both now fall back to a safe default, so futureDioExceptionTypeadditions won't break analysis again. - Applied
dart formatacross the package for a cleanpub.devstatic analysis score.
Changed #
- Reworded the package description and README intro to explicitly mention
"REST API client" and "API provider" for better
pub.devsearch relevance. - Swapped the
requesttopic forrestto match how comparable packages are tagged.
2.8.0 - 2026-08-17 #
Added #
- Token refresh interceptor — transparent 401 → refresh → replay flow.
Configure via
ApiProviderConfig.tokenRefresh: TokenRefreshConfig(...):- Queues all concurrent requests on 401, performs a single refresh, then replays all queued requests with the new token
- Calls
onLogoutif refresh fails or returnsnull - Configurable
refreshStatusCodes(default[401])
ApiPaginator— stateful pagination helper for offset/page APIs:loadNext()fetches the next page and appends toitemshasMore,isLoading,currentPage,reset()state accessors- Smart
itemsExtractorwith auto-detection of common wrapper keys (data,items,results,records)
2.7.0 - 2026-08-17 #
Added #
- In-memory GET response cache — configure via
ApiProviderConfig.cache: CacheConfig(ttl: ...):- TTL-based expiry, LRU eviction when
maxSizeis exceeded ApiProvider.clearCache()to invalidate all entriesApiProvider.cacheSizegetter to inspect current cache sizeApiCacheis exported for advanced use / testing
- TTL-based expiry, LRU eviction when
MultiApiProvider— named registry for independentApiProviderinstances:MultiApiProvider.register(name, provider)— register by nameMultiApiProvider.of(name)— retrieve anywhere, throwsStateErrorif missingMultiApiProvider.has(name),unregister(name),clear(),registeredNames
2.6.0 - 2026-08-17 #
Added #
- Auto-retry interceptor — configure via
ApiProviderConfig.retry: RetryConfig(...):- Retries on
connectionTimeout,receiveTimeout,sendTimeout,connectionError, and HTTP 5xx errors - Does not retry on 4xx client errors or cancelled requests
- Supports constant delay (default) or exponential back-off
(
useExponentialBackoff: true) - Per-request override: pass
retryConfig:to any HTTP method to override the global config for that call - Disable for one request:
retryConfig: RetryConfig.none
- Retries on
- Request deduplication — enable via
ApiProviderConfig.deduplicateRequests: true:- Identical in-flight GET requests (same URL + params) are coalesced into one network call; all callers receive the same response
RetryConfigmodel — exported for use in config and per-request overrides
2.5.0 - 2026-08-17 #
Added #
upload()— dedicated multipart/FormDataPOST method withonSendProgressandonReceiveProgresstracking; setsmultipart/form-datacontent type automatically, keeping it distinct from the genericpost()methodhead()— HTTP HEAD method for checking resource existence or inspecting headers without downloading the response bodyisInitializedgetter onApiProvider— safe guard against calling methods beforeinit()or after the provider has been closedsendTimeoutinApiProviderConfig(default 30 s) — wired intoBaseOptions.sendTimeoutso upload/send stalls are caught correctlyfollowRedirectsinApiProviderConfig(defaulttrue) — exposes the Dio on/off redirect toggle alongside the existingmaxRedirectsvalidateStatusinApiProviderConfig— lets callers decide which HTTP status codes count as success (e.g., treat 201/204 as success)headersfield onApiResponse— exposes the raw response headers (Map<String, List<String>>) for cache-control, pagination cursors, etc.requestDurationfield onApiResponse— records the total elapsed time of the request viaStopwatchfor client-side performance monitoringcopyWith()onApiResponse— immutable transform helper for tests and middleware layerstoString()override onApiResponse— human-readable summary for loggingisLoading,isSuccess,isError,isEmpty,isIdleboolean getters onApiProviderController— convenient shorthands for the most common status checksreset()onApiProviderController— restores toidleand clearsresponsein a single callpreviousStatusfield onApiProviderController— tracks the state before the latest transition, useful for conditional UI (e.g., "was loading before")- Auto-
emptydetection inApiProviderController.success()— automatically transitions toemptywhendataisnull, an emptyList, or an emptyMap, removing the need for manualcontroller.empty()calls transitionDuration,switchInCurve,switchOutCurveparams onApiProviderUi— lets callers control theAnimatedSwitchertiming and easing without forking the widgettransitionBuilderparam onApiProviderUi— expose the fullAnimatedSwitcher.transitionBuilderfor custom slide/scale/fade effects
Fixed #
ApiProviderUi.didUpdateWidget— the widget now correctly removes the old controller listener and attaches to the new one when the controller instance is swapped at runtime, preventing stale listener leakspost()dataparameter widened fromMap<String, dynamic>?todynamicto avoid a type error when callers pass aFormDataobject directly
2.4.0 - 2026-08-17 #
Security #
requestLoggernow defaults tofalse— prevents Authorization tokens and response bodies from being logged in production builds (S2)- Added
assertonApiProviderConfig.authorizationto catch non-String values at development time (S1) - Narrowed
setAuthorisation()parameter fromdynamictoString?(S1)
Performance #
init()now calls_dio?.close(force: true)before creating a new Dio instance, preventing resource leaks on repeated initialisation (P1)- Fixed
listen()memory leak — callbacks are now stored in aMapand can be removed via the newunlisten()method; repeatedlisten()calls with the same callback are idempotent (P2) - Fixed crash when API response body is a
List,String, or binary blob —response.data['message']is now guarded with anis Mapcheck (P3) ApiProviderUinow skipssetStatewhen the controller status hasn't actually changed, eliminating redundant widget rebuilds (P4)
Added #
ApiProvider.create()factory for creating independent instances when multiple backends with different configs are needed concurrently (D1)ApiProviderController.unlisten()— pair tolisten()for removing callbacks without holding a closure reference (P2)ApiProviderController.dispose()override that clears all wrapped listeners on teardown (P2)
Fixed #
- Added
assert(savePath.isNotEmpty)todownload()and documented that the method is not supported on Web (D3) - Updated stale widget tests for
IdleWidgetandEmptyWidgetto match the output introduced in v2.3.0 (D2)
2.3.0 - 2026-08-17 #
Added #
- Library-level dartdoc comment for the
easy_api_providerexport file - Constructor-level doc comments on
ApiProviderControllerandApiProviderUifor 100% public API documentation coverage
Fixed #
- Default widgets (
IdleWidget,LoadingWidget,SuccessWidget,ApiErrorWidget,EmptyWidget) now have complete dartdoc comments EmptyWidgetdisplayed incorrect "Success" text — now correctly shows "Empty"IdleWidgetnow rendersSizedBox.shrink()instead of a visibleText('Idle')label- Made
SuccessWidgetandApiErrorWidgetbodiesconstfor better performance
2.2.0 - 2026-06-03 #
Added #
- Animated preview GIF showcasing the example application
- Preview section in README
2.1.0 - 2026-06-02 #
Added #
- Full example application demonstrating all package features (CRUD, download, interceptors, auth)
- SEO-friendly pub.dev metadata and documentation
Fixed #
- Static analysis issues resolved
- Removed unused local variables in config tests
Changed #
- Excluded coverage directory from published package
2.0.0 - 2026-06-02 #
Breaking Changes #
- Bumped minimum Dart SDK from
>=2.18.0to>=3.0.0(enables Dart 3 features)
Added #
- Comprehensive test suite: 42 unit/widget tests + integration test suite
AnimatedSwitcherfor smooth cross-fade transitions between UI states inApiProviderUi- Exhaustive
DioExceptionTypeerror handling covering all 8 cases (connectionTimeout, sendTimeout, receiveTimeout, badResponse, cancel, connectionError, badCertificate, unknown)
Fixed #
- Header overwrite bug:
init()no longer overwrites all headers including Authorization whenconfig.headersis provided - URL double-slash bug: request URLs are now correctly constructed without duplicate slashes
- Listener leak in
ApiProviderUi: properly removes listeners indispose()withmountedguard - Circular imports: all internal files now use direct
package:imports instead of barrel file imports
Changed #
- Refactored HTTP methods (
get,post,put,patch,delete,download) to use a shared_requesthelper, eliminating ~400 lines of duplicated try/catch logic - Default widgets (
IdleWidget,LoadingWidget, etc.) now includeValueKeyfor proper widget reconciliation
