op_rest_api_client 0.15.3
op_rest_api_client: ^0.15.3 copied to clipboard
A lightweight and flexible Dart HTTP client for RESTful APIs with structured error handling via op_result and support for identity-based authentication and token refresh.
Changelog #
0.15.3 - 2025-08-18 #
Fixes #
- Fixed dartdoc formatting in
opRestApiBodyEncoderto prevent pub.dev analysis warnings (List<int>now properly documented as code).- Restores full pub points (50/50).
Documentation #
- Updated installation instructions in
README.md:- Now recommends using
dart pub add op_rest_api_client. - Added a dynamic Pub version badge instead of hard-coding a version number.
- Now recommends using
0.15.2 - 2025-08-17 #
Fixes #
- Fixed an issue where API requests retried after a token refresh could fail with
400 Bad Request.- Root cause: request bodies were being double-encoded on retry, especially for JSON payloads.
- Now, the retry path reuses the original
body/encodedBodycorrectly, avoiding re-encoding.
- Fixed a bug in
opRestApiBodyEncoderwhere JSONStringbodies could be incorrectly re-encoded, producing invalid JSON.
Enhancements #
- Upgraded
httpdependency to^1.5.0for bug fixes and new features (request abort support, IOClient stability improvements). opRestApiBodyEncoderimprovements:- Now accepts
String? contentType(nullable). - For
application/json:Stringvalues are passed through unchanged.Map/Listvalues are properly JSON-encoded.
- For
application/x-www-form-urlencoded:- Supports pre-encoded
StringorMap/Map<String,String>(URL-encoded automatically).
- Supports pre-encoded
- For unsupported or missing content type:
- Passes through
String/List<int>unchanged, - Falls back to
toString()for other types.
- Passes through
- Now accepts
- Default
Content-Type: application/jsonheader is now added only when the client is going to JSON-encode aMap/List.
This prevents incorrect headers when callers provideencodedBodyor non-JSON payloads.
0.15.1 - 2025-07-22 #
- Added
dnsFailuretoOpRestApiErrorTypeto distinguish DNS resolution issues from other network errors. - Upgrade http package to latest version (1.4.0)
0.15.0 - 2025-07-14 #
Breaking changes #
OpRestApiIdentity.authorizationHeader()now returnsString?instead ofString.- Return
nullto omit the header entirely.
- Return
OpRestApiErrorType.networkErrorhas been removed and replaced with three more specific error types:networkOffline: device has no internet connection.networkUnreachable: the device is connected but cannot reach the server (e.g., DNS failure, socket exception, timeout).gatewayError: the server responded with a 502 or 504 gateway error.- Unified identity header handling: Removed
authorizationHeader()fromOpRestApiIdentity. Useheaders()instead and includeAuthorizationas a regular entry if needed.
Enhancements #
- Improved error classification for more accurate handling and messaging of network-related failures.
0.14.1 - 2025-04-25 #
Enhancements #
- Fixed an issue in the README file.
- Updated
ExceptionHandlerto classifyClientExceptionas a network error. - Updated description in
pubspec.yamlto mention support forop_resultand identity-based token handling. - Added
homepagelinks inpubspec.yaml. - Upgraded dependencies to latest stable versions.
0.14.0 - 2025-03-07 #
Added #
OpRestApiEndpointas a replacement for raw endpoint strings.endpointMapnow maps user-definedApiEndpointEnumvalues toOpRestApiEndpointinstead ofString.
customValidatoras a replacement forerrorHttpStatusCodesandsuccessHttpStatusCodes,send()as the new unified request method.
Breaking Changes #
- Removed
sendGet,sendPost,sendPut,sendPatch, andsendDelete- The HTTP method is now determined directly from
OpRestApiEndpoint.
- The HTTP method is now determined directly from
- Removed
successHttpStatusCodesanderrorHttpStatusCodes.- These were previously used to determine response success and failure based on predefined status codes.
- This functionality is now fully replaced by
customValidator, which allows more flexible validation based on response body and status code.
- Removed
enumValuesandendpointMap. - Renamed
ApiClientMethodstoOpRestApiClientMethods - Renamed
ApiErrorTypetoOpRestApiErrorType - Renamed
IdentitytoOpRestApiIdentity - Renamed
restApiBodyEncodertoopRestApiBodyEncoder
Migration Guide #
-
Update endpointMap to use OpRestApiEndpoint instead of String:
const Map<ApiEndpoints, OpRestApiEndpoint> apiEndpointMap = { ApiEndpoints.getUser: OpRestApiEndpoint('/user', OpRestApiClientMethods.get), ApiEndpoints.updateUser: OpRestApiEndpoint('/user/update', OpRestApiClientMethods.put), }; -
Replace calls to
sendGet(),sendPost(), etc. withsend():// Before await apiClient.sendGet(endpoint: ApiEndpoints.getUser);// After await apiClient.send(endpoint: ApiEndpoints.getUser); -
If you previously used
successHttpStatusCodesanderrorHttpStatusCodes, migrate tocustomValidator:// Before (Using `successHttpStatusCodes` & `errorHttpStatusCodes`) final result = await apiClient.send( endpoint: MyApiEndpoints.getUser, successHttpStatusCodes: [200, 202], // Considered successful errorHttpStatusCodes: {OpRestApiErrorType.notFound: [404]}, );// After (Using `customValidator`): OpResult<http.Response, MyCustomError>? myValidator(http.Response response) { if (response.statusCode == 200 || response.statusCode == 202) { return OpResult.success(response); } if (response.statusCode == 404) { return OpResult.failure(OpError(type: MyCustomError.notFound)); } return null; // Fallback to default handling } final result = await apiClient.send( endpoint: MyApiEndpoints.getUser, customValidator: myValidator, );
0.13.0 - 2025-03-03 #
Breaking Changes #
- Renamed package
json_api_clienttoop_rest_api_client-
Update all
importstatements:// No longer valid: import 'package:json_api_client/json_api_client.dart'; // Use this instead: import 'package:op_rest_api_client/op_rest_api_client.dart'; -
Update
pubspec.yamldependencies:dependencies: op_rest_api_client: ^0.13.0
-
0.12.0 - 2025-03-03 #
Breaking Changes #
- Renamed
ApiOpResulttoOpResultfor consistency with the package naming convention. - Renamed
OpResultErrortoOpErrorto simplify error handling terminology. - Renamed
ApiOpResultErrorTypetoApiErrorTypeto better reflect its role as an API-specific error type.
These changes require updating all references to the renamed classes in your codebase.
0.11.1 - 2025-02-27 #
Upgrades & Improvements #
- Upgraded to the latest
op_resultlibrary: - Refactored codebase to align with
op_resultchanges:- Updated all
failure()calls to use the new factory constructor. - Ensured compliance with the new multiple error handling system.
- Updated all
0.11.0 - 2025-02-24 #
New Features #
-
Added Support for
PUT,PATCH, andDELETEMethods-
The API client now supports all major HTTP request methods, including:
sendPut()sendPatch()sendDelete()
-
These methods function similarly to
sendPost(), allowing request bodies and encoded data. -
Usage Examples:
// PUT Request final response = await apiClient.sendPut( apiEndPoint: ApiEndpoints.updateUser, identity: userIdentity, body: {"name": "Updated Name", "email": "[email protected]"}, ); // PATCH Request final response = await apiClient.sendPatch( apiEndPoint: ApiEndpoints.partialUpdate, identity: userIdentity, body: {"status": "active"}, ); // DELETE Request final response = await apiClient.sendDelete( apiEndPoint: ApiEndpoints.deleteAccount, identity: userIdentity, );
-
-
Enhanced API Consistency
- The API client now follows a unified request structure for
POST,PUT,PATCH, andDELETE, ensuring consistent handling of request bodies. bodyandencodedBodywork the same way across all methods.
- The API client now follows a unified request structure for
-
Updated Documentation & Macros
- The DartDoc macros now clarify that:
bodyis optional forDELETErequests.headers["authorization"]cannot be used together withidentity, but other headers can be combined.
- The DartDoc macros now clarify that:
0.10.0 - 2025-02-22 #
Enhancements #
-
Added Support for
x-www-form-urlencodedRequest Body Encoding- The API client now supports sending requests using
application/x-www-form-urlencoded. - If
encodedBodyis provided, it takes precedence overbody, ensuring full control over pre-encoded data. - If
encodedBodyisnull, the client automatically encodesbodybased on thecontent-typeheader. - Encoding behavior:
"application/json"(default) → Encoded as JSON."application/x-www-form-urlencoded"→ Encoded as a query string.
- Example Usage:
final response = await apiClient.sendPost( apiEndPoint: ApiEndpoints.login, identity: null, body: {"email": "[email protected]", "password": "123456"}, ); // Defaults to JSON encodingfinal response = await apiClient.sendPost( apiEndPoint: ApiEndpoints.login, identity: null, headers: {"content-type": "application/x-www-form-urlencoded"}, body: {"email": "[email protected]", "password": "123456"}, ); // Automatically encodes as form-urlencodedfinal response = await apiClient.sendPost( apiEndPoint: ApiEndpoints.login, identity: null, encodedBody: "email=user%40example.com&password=123456", headers: {"content-type": "application/x-www-form-urlencoded"}, ); // Uses pre-encoded body
- The API client now supports sending requests using
-
New Public Helper:
restApiBodyEncoder- The package now exports
restApiBodyEncoder, a utility function to encode request bodies according to thecontent-type. - Users can use this function if they need to manually encode a request body before passing it to
encodedBody. - Example Usage:
import 'package:rest_api_client/rest_api_client.dart'; final String encoded = restApiBodyEncoder( {"email": "[email protected]", "password": "123456"}, "application/x-www-form-urlencoded", )!; print(encoded); // Output: email=user%40example.com&password=123456 - This allows consistency between manual encoding and the library's automatic encoding logic.
- The package now exports
-
Updated
sendPostDocumentation- Clarified that
bodyis encoded based on thecontent-typeheader, defaulting toapplication/json. - Explicitly documented that
encodedBodytakes precedence if provided. - Improved examples for JSON, form-urlencoded, and manually encoded bodies.
- Clarified that
0.9.0 - 2025-02-14 #
Breaking Changes #
-
Renamed
rawTokentoidentityData- This change makes the field name more representative of its purpose, indicating that it holds identity-related authentication data rather than just a raw token.
- Migration Guide:
- Update all instances of
rawTokentoidentityData.
- Update all instances of
- Example:
final AuthIdentity identity = ...; print(identity.rawToken); // No longer valid print(identity.identityData); // Use this instead
-
Renamed
authToken()toauthorizationHeader()- This change clarifies that the method returns a properly formatted HTTP
Authorizationheader instead of just a raw token. - Migration Guide:
- Replace calls to
authToken()withauthorizationHeader().
- Replace calls to
- Example:
final Identity identity = ...; final String token = identity.authToken(); // ❌ No longer valid final String header = identity.authorizationHeader(); // ✅ Use this instead
- This change clarifies that the method returns a properly formatted HTTP
Enhancements #
- Improved naming conventions for better clarity and maintainability.
- Strengthened the API client's consistency in handling authentication.
Migration Notes #
- All implementations of
Identity<T>must update their method signatures to reflect the new names. - If using
authToken()in API request headers, replace it withauthorizationHeader(). - If storing
rawToken, update it toidentityData.
0.8.0 - 2025-02-13 #
Added #
-
Support for Token Refresh:
- The API client now supports automatic token refresh, ensuring persistent authentication without requiring the user to log in again when their access token expires.
- When an API request fails with 401 Unauthorized, the client will attempt a token refresh once before retrying the request.
- If the refresh is successful, the request is retried seamlessly using the new access token.
-
refreshMethod inIdentity:- This new method is responsible for invoking the refresh token flow.
- It is automatically triggered when the access token is expired or when a 401 response is received from the API.
Fixes & Improvements #
- Optimized API request handling to automatically retry requests after a successful token refresh.
0.7.0 - 2025-02-12 #
Breaking Changes #
- Removed
authHeaderKeyparameter- If needed, custom authorization headers can now be passed directly through the
headersparameter in each API call. - As a result, when
identityis specified in a request, theAuthorizationheader now defaults to'Bearer $token'.
- If needed, custom authorization headers can now be passed directly through the
Enhancements #
- Flexible Authentication Handling
- Both
headersandidentitycan now be provided in a request. - However,
headers['Authorization']andidentityare mutually exclusive—ifheaders['Authorization']is explicitly set,identitywill be ignored.
- Both
0.6.0 - 2025-02-01 #
Added #
- Added support for custom headers in
OpRestApiClient.- Users can now pass an optional
headersparameter in API requests, allowing full control over authentication and custom headers. - If
headersis provided,identityis ignored, making the library independent of theIdentityclass and more flexible for various authentication methods. - This enables the use of API keys, session-based auth, and other custom headers without modifying the core API client.
- Users can now pass an optional
0.5.0 - 2025-01-14 #
Added #
- Added support for an optional
onUnauthenticatedcallback inOpRestApiClient. This callback is triggered when a request returns anunauthenticatederror, enabling custom handling of unauthenticated states, such as logging out or displaying a user message. - The
onUnauthenticatedcallback supports both synchronous and asynchronous functions, allowing flexibility for diverse use cases.
0.4.0 - 2025-01-13 #
Added #
- Introduced
authToken()inIdentity, providing a method to retrieve the authentication token regardless of the typeTof theIdentity. This enhances flexibility and ensures a consistent way to access tokens in various implementations. - Renamed
tokeninIdentitytorawTokento better distinguish it from theauthToken()method, which provides a processed or extracted authentication token.
0.3.0 - 2025-01-13 #
Added #
- Made
Identitya generic class, enabling the usage of tokens with types other thanString. This increases flexibility and allows for better type safety in applications that use custom token types.