flutter_api_client 1.1.0
flutter_api_client: ^1.1.0 copied to clipboard
Type-safe HTTP client for Flutter/Dart with retries, cache, dedup, refresh-queue auth, cancel tokens, and a spec-driven mock + docs + backend-guide generator.
1.1.0 #
Release Date: 2026-06-23
Type: Minor Release (streaming, offline-queue replay, resilience + auth hardening, audit fixes)
Breaking Changes: None (additive; RequestOptions.retryPolicy/cachePolicy are now statically typed)
This release adds a true streaming download path and an offline-queue replay engine, hardens retries / caching / dedup / GraphQL APQ and the concurrent-401 auth refresh flow, and fixes a set of codegen and documentation issues found in a full audit. Fully backward compatible with 1.0.3.
Security #
AuthInterceptor: the token-change fingerprint used by the concurrent-401 staleness guard now uses SHA-256 instead ofString.hashCode, removing the collision risk that could mask a real token rotation (and fire a redundant refresh) and making the "non-reversible" guarantee actually hold. The fingerprint remains internal and is stripped before the wire. Therefreshcontract is now documented explicitly: it must persist the new token before completing; wrap slow backends inCachedTokenStorage.
Added #
- Offline queue replay engine:
OfflineQueueReplayerdrains the queue increatedAtorder and re-issues each request through the client (re-attaching a fresh auth token). Transient failures are re-enqueued with an attempt count; requests are dead-lettered aftermaxAttemptsto prevent poison-message loops.QueuedRequestnow carries anattemptsfield (defaults to 0 for existing persisted records). - Real streaming responses:
ApiClient.stream()returns anHttpStreamResponsewhose body is delivered as a live byte stream instead of being buffered.DefaultHttpAdapterimplements the new optionalStreamingHttpAdaptercapability; adapters that don't support it fall back to buffering transparently. MemoryCacheStorebyte bound: optionalmaxBytescap so the cache evicts by total body size, not just entry count.
Fixed #
- Response body copied three times: the receive path now uses a
BytesBuilder, coalescing the body in a single pass instead ofexpand().toList()+Uint8List.fromList. Retry-Aftercould wedge a request: the header is now clamped tomaxDelay, negative values are rejected, and the HTTP-date form is parsed.- Correlated retry jitter: retries now use a shared RNG and full jitter
(uniform in
[0, capped]) so concurrent clients decorrelate under load. - Dedup deadlock on retry: a retried deduped request no longer awaits its
own in-flight completer; followers also time out (
waitTimeout) instead of hanging if a leader never completes. - GraphQL APQ hash: the default
hashQuerynow produces a real SHA-256 hex digest, so the persisted-query fast path can match a server-registered document (the old placeholder guaranteed a miss + full-document fallback). The fallback request after aPersistedQueryNotFoundmiss now carries the full document and thesha256Hashtogether, so the server can register the query and later calls hit the fast path (previously the hash was dropped on fallback, so APQ could never engage). - Auth token could leak past an explicit
includeToken: false: when a request supplied both a method-levelincludeToken: falseand a non-nullRequestOptions, the options default (true) silently won and theAuthorizationheader was attached anyway. Token attachment is now fail-safe: it requires both sources to permit it. - Duplicate
Content-Typeheaders: a caller header override spelled with different casing (e.g.content-type) no longer emits a second, conflictingContent-Type; header merging is now case-insensitive (latest value wins). stream()leaked the transport client on error responses: a non-2xx streaming response now drains the unbuffered body so the streaming adapter's ownedhttp.Clientis closed exactly once instead of leaking.TestGenerator: generated test source now escapes',$,\, and newlines in example bodies (previously emitted non-compiling Dart), and skips endpoints whose HTTP method the client has no verb for (e.g.HEAD) instead of emitting an uncompilableclient.head(...)call.CurlLogger: uses the portable'\''POSIX idiom to embed single quotes, so emitted cURL commands stay paste-able when a header or body contains a quote.bin/gen.dart: relative-import computation normalises path separators, sodart run flutter_api_client:genworks on Windows.Schema.validate: an unknown schematypenow fails validation instead of silently passing.InMemoryOfflineQueueStore.drain: returns requests increatedAtorder, matching theOfflineQueueStorecontract andHiveOfflineQueueStore.CachedTokenStorage.clear: awaits the delegate before dropping the cache, so a failed delegate clear no longer resurrects a "cleared" token on next read.
Changed #
RequestOptions.retryPolicy/cachePolicyare now typedRetryPolicyInterface?/CachePolicyInterface?(declared incore) instead ofObject?, giving compile-time safety. Existing code passingRetryPolicy/CachePolicyinstances is unaffected.CachePolicy.staleWhileRevalidatedocs now describe the actual behaviour (serve-fresh, revalidate-on-stale); removed a dead internal revalidate header.
Deprecated #
ApiClientInterface— single-implementation interface with no injection point. Depend onApiClientdirectly (Dart can fake concrete classes). Scheduled for removal in 2.0.0.
Dependencies #
- Promoted
cryptoto a direct dependency (used for APQ hashing).
1.0.3 #
Release Date: 2026-05-31
Type: Patch Release (Security hardening + Dependency refresh)
Breaking Changes: None
This release hardens request handling and logging, refreshes direct dependencies to current compatible versions, and aligns the package documentation with the shipped runtime behavior. Fully backward compatible with 1.0.2.
Fixed #
- Internal Header Leakage: Client-only
x-fac-*control headers are now stripped before requests reach the transport layer - Retry Safety: Response-based retries now respect
safeMethods, preventing automatic retries of mutating methods unless explicitly configured - Offline Queue Credentials:
OfflineQueueInterceptorno longer persistsAuthorizationheaders, preventing stale-token replay from on-disk queues - Logger Redaction: cURL and pretty loggers now redact sensitive JSON body keys and sensitive response headers more consistently
- Builder Compatibility: Updated generated-spec builder logic for current
source_gen/ analyzer APIs
Documentation #
- README.md: Added explicit permission guidance, corrected retry/cache/offline-queue semantics, refreshed logger examples, and updated test commands
- TESTING.md: Switched package test instructions to
flutter testand aligned filters/examples with the current workflow - ARCHITECTURE.md: Updated retry and cache behavior descriptions to match the runtime implementation
- Library Dartdoc: Refreshed release notes in
lib/flutter_api_client.dart
Quality Improvements #
- Dependency Freshness: Bumped direct runtime/tooling constraints to current compatible versions and removed the unused direct
metadependency - Regression Coverage: Added tests for internal header stripping, non-safe retry behavior, offline queue auth stripping, and logger redaction of sensitive payloads
- Verification:
dart analyze,flutter test,flutter testinexample/,dart pub outdated --json --up-to-date --no-dev-dependencies --no-dependency-overrides, anddart pub downgrade --no-example && dart analyze
Upgrade Guide #
dependencies:
flutter_api_client: ^1.0.3
No code changes required for existing callers.
1.0.2 #
Release Date: 2026-05-31
Type: Patch Release (Core correctness + Documentation)
Breaking Changes: None
This release tightens HTTP response parsing, improves maintainability in the core request path, and aligns the package documentation with the shipped API surface. Fully backward compatible with 1.0.1.
Fixed #
- HTTP Parse Classification: Successful
ResponseType.jsonresponses that contain malformed JSON now returnFailure(ParseError)instead of degrading into nullable/unknown behavior - Text/HTML Payload Handling: Successful JSON-mode responses with obvious text or HTML payloads now return
Failure(ParseError) - No-Content Success Semantics: Empty successful JSON responses are handled explicitly and continue to decode to
null
Internal Improvements #
- ApiClient Decomposition: Split request option resolution, header construction, payload building, and response decoding into smaller private helpers
- Error Mapping: Kept non-2xx malformed payloads classified as
HttpErrorso HTTP status remains the primary failure signal
Documentation #
- README.md: Removed stale
CustomApiResponse/client.request()documentation and aligned all HTTP result examples withApiResult<T> - ARCHITECTURE.md: Updated the architecture narrative to reflect the shipped result type and parse behavior
- Library Dartdoc: Refreshed release notes in
lib/flutter_api_client.dart
Quality Improvements #
- Regression Coverage: Added tests for malformed successful JSON, successful HTML/text payloads in JSON mode, explicit empty-body success handling, and malformed non-2xx payload preservation
- Verification:
flutter testpasses with 138 tests
Upgrade Guide #
dependencies:
flutter_api_client: ^1.0.2
No code changes required for existing callers.
1.0.1 #
Release Date: 2026-05-12
Type: Patch Release (Bug fixes + Documentation)
Breaking Changes: None
This release focuses on improving documentation, fixing generated code issues, and ensuring the package follows all industry standards. Fully backward compatible with 1.0.0.
Fixed #
- Test Generation: Fixed undefined
specreference in generated test files (test_generator.dart)- Generated tests now correctly import and reference the actual spec variable
specplaceholder replaced with actual spec variable name (e.g.,mySpec)- All generated tests pass without manual modifications
- Import Cleanup: Fixed unused import warnings in generated test scaffolds
- Example Tests: Improved example test structure with proper package imports
- Code Formatting: Formatted 64 Dart files across the entire codebase for consistency
Documentation #
- README.md: Major enhancement with 1000+ lines of comprehensive documentation
- Added "Features at a Glance" section documenting 55+ features across 6 categories
- Enhanced feature comparison table (dio vs http vs flutter_api_client)
- Added "Key Advantages" section highlighting unique benefits
- Updated all version references from 2.0.0 to 1.0.1
- Improved quick start guide with clearer examples
- Better table of contents organization
- CONTRIBUTING.md (NEW): Complete contribution guidelines
- Code style conventions following Effective Dart
- Commit message format using Conventional Commits
- Pull request process and templates
- Testing requirements and examples
- Project structure overview
- 256 lines of guidance for contributors
- ARCHITECTURE.md (NEW): Internal architecture documentation
- High-level system architecture diagrams
- Component interaction flows and data flow
- Detailed interceptor chain explanation
- Design decisions and rationale for key features
- Performance considerations and optimizations
- Token storage architecture
- Future roadmap and planned enhancements
- 467 lines of technical documentation
- example/README.md: Completely rewritten
- Tab-by-tab feature demonstrations
- Real API usage examples (DummyJSON, JSONPlaceholder, Dog CEO, Open Trivia)
- Running instructions for all platforms (iOS, Android, Web, Desktop)
- Code structure overview
- Key takeaways and learning objectives
- 140 lines of practical guidance
- docs/RELEASE_NOTES_1.0.1.md (NEW): Comprehensive release documentation
- Detailed bug fixes and improvements
- Feature highlights and statistics
- Migration guide (no migration needed)
- Industry standards compliance checklist
- Future roadmap for 1.1.0
- docs/PACKAGE_REVIEW_SUMMARY.md (NEW): Complete quality assessment
- Production readiness checklist
- Code quality metrics (134 tests, 0 errors)
- Security review
- Performance review
- Compatibility matrix
- API_SERVICES_GUIDE.md: Updated all version references to 1.0.1
- TESTING.md: Enhanced with additional test patterns
- lib/flutter_api_client.dart: Expanded library-level documentation
- Comprehensive feature overview in dartdoc
- Quick start code example
- Version 1.0.1 release notes
Quality Improvements #
- Test Suite: All 134 tests passing (100% pass rate)
- Zero test failures
- Improved test coverage for edge cases
- Fixed flaky tests in example project
- Code Analysis:
- Zero errors
- 2 acceptable warnings (generated files)
- 65 info messages (style suggestions, SDK deprecations)
- All critical issues resolved
- Industry Standards Compliance:
- ✅ Semantic Versioning (SemVer 2.0.0)
- ✅ Conventional Commits documentation
- ✅ Keep a Changelog format
- ✅ Effective Dart style guide
- ✅ MIT License
- ✅ Comprehensive examples
- ✅ API documentation (dartdoc)
- ✅ Architecture documentation
- ✅ Contributing guidelines
Statistics #
- Documentation: 10 comprehensive markdown files (5 new, 5 updated)
- Tests: 134 passing (previously 107, more edge cases discovered and tested)
- Code Quality: 64 files formatted, 0 errors, >90% coverage maintained
- Package Size: No significant change from 1.0.0
Notes #
- This release maintains 100% backward compatibility with 1.0.0
- No dependency updates required
- All features from 1.0.0 work identically
- Recommended for all users to upgrade for better documentation and fixed test generation
Upgrade Guide #
dependencies:
flutter_api_client: ^1.0.1
Then run:
flutter pub upgrade flutter_api_client
No code changes required. Regenerate tests if using spec system:
dart run flutter_api_client:gen --only tests
1.0.0 #
Major redesign. Bumps the package above feature parity with dio while
keeping the surface focused. Breaking changes — see the migration
section in the README.
Added (GraphQL) #
GraphQLClientwrapper aroundApiClientwithquery,mutation, typedGraphQLResponse<T>, optional decoder for thedatafield, GraphQL error parsing, and automatic-persisted-queries (APQ) support.GraphQLException+GraphQLErrortypes for typed error handling.ApiSpec.graphql(...)section +GraphQLOperation/GraphQLErrorExample. Declare queries, mutations, and subscriptions alongside REST endpoints.SpecMockAdapternow routesPOST /graphql(or your chosen endpoint) to declared operations, validates variables against theirSchema, and supportsstatusOverrides: {'GQL OperationName': code}.MarkdownDocGeneratorrenders a GraphQL section per operation.BackendGuideGeneratorrenders a GraphQL section: operation table, derived SDL (Query/Mutation/Subscription), variable tables, exampledata, resolver skeletons, and optional framework snippets (Express + Apollo, FastAPI + Strawberry, Go + gqlgen). The acceptance checklist now covers GraphQL operations too.
Added #
- Pluggable
HttpAdapter— swappackage:httpforcupertino_http,cronet_http, or aMockAdapterfor tests. MockAdapter— route-based mock transport with request capture.- Spec-driven endpoints — author one
ApiSpecand get:- a fully working
SpecMockAdapterfor tests (schema-validates request bodies), - an OpenAPI 3.1 document (
OpenApiGenerator.toJsonString()/toYaml()), - a Markdown API reference (
MarkdownDocGenerator), - a backend-implementation guide (
BackendGuideGenerator) with route table, validation rules, status-code matrix, handler skeletons, and optional Express/FastAPI/Gin code snippets.
- a fully working
- Real multi-request
CancelToken— one token cancels many requests without disturbing unrelated traffic. RetryInterceptor+RetryPolicy— exponential backoff, jitter, per-request override, andRetry-Afterheader support.- Concurrent-safe
AuthInterceptor— 401 triggers exactly one refresh call; every concurrent request waits and is replayed. CacheInterceptor—networkFirst,cacheFirst,staleWhileRevalidate,cacheOnlymodes with TTL and ETag/If-None-Matchrevalidation. PluggableCacheStorewith a built-inMemoryCacheStore.DedupInterceptor— coalesces in-flight identical GETs.- Logging interceptors —
CurlLogger(ready-to-paste cURL) andPrettyLogger(ANSI, header redaction). OfflineQueueInterceptor— persists failed mutations via a pluggableOfflineQueueStorefor later replay.- Sealed
ApiResult<T>withSuccess/Failureand exhaustivewhen. - Generic
CustomApiResponse<T>with adecoderparameter on every verb. - Typed exceptions:
NetworkError,TimeoutError,CancelError,HttpError,ParseError,UnknownError. RequestOptionsupgraded withqueryParameters,responseType,cancelToken,onSendProgress,onReceiveProgress, and per-request retry/cache overrides.- Upload/download progress callbacks via streamed requests/responses.
FormData.fromMaphelper for multipart uploads.buildQueryString/buildUrihelpers with list & nested-map support.
Fixed #
- Cancelling a request no longer closes the shared global HTTP client and
break unrelated in-flight requests. Each request now uses its own
http.Client. - Treats any
2xx(not only 200/201/204) as success.
Changed #
ApiClientverbs are now generic (get<T>,post<T>, …) with optionaldecoderandT Function(Object json)?.- Interceptors are configured as a single ordered list
(
ApiClientConfig(interceptors: [...])). The legacyrequestInterceptor/responseInterceptorfields were removed.
Migration #
await client.get('users')⇒await client.get<dynamic>('users').final res = await client.get(...); if (res.isSuccess) ...still works.- For new code prefer
client.get<User>('users/me', decoder: (json) => User.fromJson(json as Map<String, dynamic>))which returnsApiResult<User>. - Replace single-interceptor config with the
interceptors:list.
0.1.0 #
- Initial release with API client implementation.
- Support for GET, POST, PUT, PATCH, DELETE.
- Custom token storage and CachedTokenStorage for fast token access.
- Request/response interceptors.
- Per-request options (headers, timeout, base URL override).
0.0.1 #
- Initial scaffolding.