backend_driven_ui 0.3.0
backend_driven_ui: ^0.3.0 copied to clipboard
Server-Driven UI framework for Flutter with ApiWidget - build data-driven interfaces without FutureBuilder boilerplate.
Changelog #
All notable changes to this project will be documented in this file.
0.3.0 - 2026-04-16 #
Added #
- 4 screenshots added to pub.dev gallery showcasing the WhatsApp-clone example (Chats, Status, Calls, Settings screens)
BduiHttpClientabstract class — inject a custom HTTP backend intoApiWidgetfor testing or alternative HTTP libraries without modifying widget codeDefaultBduiHttpClient— default implementation backed byApiClient, used automatically when nohttpClientis providedApiRequestmodel — bundles all API call parameters into a reusable, composable value object withcopyWith()support; pass toApiWidget(request: ...)instead of individual paramsHttpMethodenum (get,post,put,delete,patch) — replaces raw string method values; exposes.valuefor the uppercase string representationApiWidget.httpClient— inject aBduiHttpClientimplementation per-widget (useful for mocking in tests)ApiWidget.request— shorthand: pass oneApiRequestinstead of separateendpoint,method,headers,body,cacheDuration,maxRetries,timeoutparamsBduiConfig.defaultContentType— configurable defaultContent-Typeheader (default:'application/json')
Changed #
ApiWidget.methodtype changed fromStringtoHttpMethod(default:HttpMethod.get)ApiWidget.maxRetrieschanged fromint = 3toint?—nullresolves toBduiConfig.defaultMaxRetriesso changing config once applies everywhereApiWidget.timeoutchanged fromDuration = const Duration(seconds: 30)toDuration?—nullresolves toBduiConfig.defaultTimeoutBackendDrivenScreen.methodtype changed fromStringtoHttpMethodBackendDrivenScreen.maxRetrieschanged fromint = 3toint?— resolves toBduiConfig.defaultMaxRetriesApiClient._fetchnow usesBduiConfig.defaultContentTypeinstead of the hardcoded string'application/json'ApiClient._refreshInBackgroundnow usesBduiConfig.defaultCacheDurationinstead of the hardcodedconst Duration(minutes: 5)
Fixed #
ApiClient._fetchnow throwsApiExceptionon invalid JSON responses instead of silently passing the raw response body to the caller —ApiWidgetandBackendDrivenScreenboth route to their error state correctlyApiWidget.didUpdateWidgetnow triggers a refetch whenwidget.requestchanges (was only watchingendpoint,method, andbody)ApiWidgeterror callback now deduplicates viadataHash(same guard already applied toonSuccess) — prevents repeatedonErrorcalls for the same errorApiWidgetnow throws immediately when bothrequestandendpointare absent instead of making a request to an empty URLRetryHandler.defaultShouldRetrynow inspectsApiException.statusCodedirectly instead of string-matching the error message — 4xx errors no longer retry, 5xx always retry, network/timeout errors retry correctlyActionHandler._handleReplacedelegates toonNavigatewhen provided (GoRouter / AutoRoute compatibility), otherwise callsNavigator.pushReplacementNamedapi_client.dart,api_cache.dart, andretry_handler.dartremoved from public exports — these are internal implementation detailsWidgetRegistry.globalrenamed toWidgetRegistry.instance(Flutter singleton convention)SchemaParser.parse()documented: widget cache is context-unaware; callclearCache()after theme or locale changes to force rebuildsUrlValidatorclass-level doc updated to document the DNS-rebinding limitation and recommend network-level controls for stricter environmentstoIconDatainSchemaConvertersexpanded from 8 to 35 icons; unknown icon names now log a warning listing all supported values- Codebase refactored for single responsibility:
builtin_widgets.dartreduced from ~1 500 lines to 68-line registration map; type converters moved toSchemaConverters; widget builders split intodisplay_builders,layout_builders,material_builders,interactive_builders,scrollable_builders,effects_builders;ActionHandlertypedefs moved toaction_callbacks.dart BackendDrivenScreen.didUpdateWidgetnow refetches the schema whenendpoint,method, orbodychanges — previously only callback changes triggered a re-initBackendDrivenScreennow accepts atimeoutparameter; previously the 30-second default was hardcoded and could not be overriddenButton,ElevatedButton,TextButton,OutlinedButton,IconButtonbuilders now route actions throughSchemaParser.createActionHandler(), ensuringonNavigate,onCustomAction,onApiSuccess,onApiError, andonLaunchUrlcallbacks set on the parser are honoured — previously these widgets created a bareActionHandlerthat ignored all parser callbacksGestureDetectorandInkWellbuilders now executeonDoubleTapandonLongPressaction maps frompropsinstead of logging a debug messageListTilebuilder now supportsonTapvia the schemaactionfieldActionHandlerapiaction now passesBduiConfig.defaultMaxRetriesandBduiConfig.defaultTimeoutto all API calls — previously these were ignored and the hardcoded SDK defaults were used regardless of configActionHandlerapiaction no longer shows a default error snackbar when anonApiErrorcallback is registered — previously both the callback and the snackbar fired simultaneouslyApiWidgetnow uses separate deduplication hashes foronSuccessandonError— previously a single shared hash could suppress one callback when the other fired with an identical hash valueApiWidget.didUpdateWidgetnow also refetches whenheaderschange, covering auth-token refresh without other param changes
Maintenance #
HttpMethod.patchnow fully implemented acrossApiClient,BduiHttpClient,DefaultBduiHttpClient,ActionHandler,ApiWidget, andBackendDrivenScreen— previously the enum value existed but all execution paths threw "Unsupported HTTP method: PATCH"ApiRequest.copyWith()body sentinel fix — passingbody: nullnow correctly clears the body on the copy; previouslynullwas silently ignored and the original body was retained- Resolved all static analysis issues in test files — unused import removed, redundant
constkeywords fixed;flutter analyzenow reports zero issues
Exports #
BduiHttpClient,DefaultBduiHttpClientnow exported from the package rootApiRequestnow exported from the package rootHttpMethodnow exported from the package root
0.2.1 - 2026-04-14 #
Fixed #
- Restored
example/in the published archive so pub.dev awards the example pub points (was incorrectly excluded in 0.2.0.pubignore) - Added missing dartdoc comments to
ActionHandlerconstructor and fields (context,onApiSuccess,onApiError,onCustomAction)
0.2.0 - 2026-04-13 #
Added #
BduiConfig.baseUrl— set a global base URL once; all relative endpoints resolve against it automaticallySchemaParser.register()— convenience method to add custom widget builders without accessing the registry directly- Named color support in JSON:
"color": "blue","color": "Colors.deepPurple","color": "#1976D2"(all Flutter color names + CSS hex + ARGB hex — any format now works) onLaunchUrlcallback onActionHandler,SchemaParser, andBackendDrivenScreen— wire inurl_launcheror any custom handler to handlelaunchUrlactions from JSON schemas- 74 tests covering
ApiCache,WidgetSchema,BduiConfig,helpers,ApiClient,SchemaWidget, and custom widget registration
Fixed #
WidgetRegistry.instancereferenced in README docs was incorrect — corrected to useSchemaParser.register()API- Cache key generation now uses a deterministic polynomial hash and sorted props keys — previously XOR-based hashing caused collisions for schemas with swapped or duplicate children
ApiClient.dispose()now guards against_performDisposal()being called more than once when multiple in-flight requests complete simultaneously- JSON response unwrapping for
ui/datakeys now validates the value is aMapbefore extracting — previously a non-Map value (e.g. String) would propagate and crash the schema parser evaluateConditionnow logs a warning with the full list of supported conditions when an unknown condition string is received, instead of silently returningfalse
Changed #
logger.dartrenamed tobdui_logger.dartfor clarity — internal change, no public API impact
Removed #
- "Early stage" disclaimer from README — the API is stable
0.1.0 - 2025-03-17 #
Added #
ApiWidget
- 🎯 Declarative API data fetching widget (FutureBuilder alternative)
- Built-in loading, success, error, and empty states
- Automatic caching with configurable TTL
- Retry logic with exponential backoff
- Polling support for real-time updates
- Success/error callbacks
- Retry button on errors
Backend-Driven UI
- 🚀
BackendDrivenScreen- Fetch and render UI from JSON schemas SchemaParser- Parse JSON into Flutter widgetsWidgetRegistry- Extensible widget system- 33 Built-in widgets:
- Layout (12): Column, Row, Stack, Center, Padding, SizedBox, Expanded, Flexible, Wrap, Spacer, AspectRatio, Container
- Display (4): Text, Icon, Image, Divider
- Material (5): Card, ListTile, CircleAvatar, Chip, ClipRRect
- Interactive (7): Button, ElevatedButton, TextButton, OutlinedButton, IconButton, GestureDetector, InkWell
- Scrollable (3): ListView, GridView, SingleChildScrollView
- Effects (2): Visibility, Opacity
- Conditional rendering (platform, screen size, theme detection)
- Widget schema caching for performance
Core Features
- 📦 Lightweight HTTP client (only
httppackage dependency) - Custom retry handler with exponential backoff
- LRU cache with TTL for API responses
- Server-controlled caching - Backend can specify cache policy per response:
cache- Cache with optional TTLnoCache- Always fetch freshrefresh- Stale-while-revalidate pattern
- Action handler system (navigate, API calls, dialogs, etc.)
- Type-safe models for requests/responses
Documentation
- 📖 Comprehensive README with examples
- JSON Schema Reference Guide (SCHEMA_REFERENCE.md)
- Working example app with multiple demos
- Inline code documentation
Technical Details #
- Zero heavy dependencies (50KB vs 350KB+ with dio)
- Production-ready error handling
- Material Design 3 support
- Platform-agnostic architecture
