https://github.com/leo1394/authenticated_http_client
An advanced authenticated HTTP client introduces `factory` feature that generates request functions based on API definitions in WYSIWYG style and supports `mock` and `silent` modes for development.
https://github.com/leo1394/authenticated_http_client
authenticated-http-client dart http-client http-interceptor http-request wysiwyg
Last synced: 19 days ago
JSON representation
An advanced authenticated HTTP client introduces `factory` feature that generates request functions based on API definitions in WYSIWYG style and supports `mock` and `silent` modes for development.
- Host: GitHub
- URL: https://github.com/leo1394/authenticated_http_client
- Owner: leo1394
- License: mit
- Created: 2025-01-25T15:29:42.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2026-01-19T06:29:18.000Z (about 2 months ago)
- Last Synced: 2026-01-19T14:52:00.152Z (about 2 months ago)
- Topics: authenticated-http-client, dart, http-client, http-interceptor, http-request, wysiwyg
- Language: Dart
- Homepage: https://pub.dev/packages/authenticated_http_client
- Size: 144 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README-EN.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
## authenticated_http_client
[](https://pub.dev/packages/authenticated_http_client)
[](https://pub.dev/packages/authenticated_http_client/score)
[](https://github.com/leo1394/authenticated_http_client/issues)
[](https://github.com/leo1394/authenticated_http_client/network)
[](https://github.com/leo1394/authenticated_http_client/stargazers)
[](https://raw.githubusercontent.com/leo1394/authenticated_http_client/master/LICENSE)
An advanced authenticated HTTP client introduces a `factory` feature that generates request futures based on API definitions in a WYSIWYG style,
with additional supports for `mock` and `silent` modes during development.
It all began with the forging pattern — `[mock] [silent] [method] /api/plan/{id}/details` — a skeletal incantation that would simplify every thing.
- `factory`: generates AJAX request functions by api URI declaration in WYSIWYG style.
- `mock`: mocking data from a local JSON file for specified requests during development.
- `silent`: suppress routing redirection for unauthorized or maintenance responses for specified request.
- `throttling`: queues excess requests using async/await for controlled upload pacing.
- request futures functions generated can be accessed by dot notation.
Language: English | [中文](README.md)
## Platform Support
| Android | iOS | MacOS | Web | Linux | Windows |
| :-----: | :-: | :---: |:---:| :---: | :-----: |
| ✅ | ✅ | ✅ | ❌️ | ✅ | ✅ |
## Requirements
- Flutter >=3.0.0 <4.0.0
- Dart: ^2.17.0
- http: ^1.3.0
- http_interceptor: ^2.0.0
## Getting started
published on pub.dev, run this Flutter command
```shell
flutter pub add authenticated_http_client
```
## Usage showcase
- Retrieve the auth_token and store it in the AuthenticatedHttpClient cache.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({ "login" : "POST /api/sign-in" });
apiService.login({"username": "demo", "passwords": "test123"}).then((response) {
// response here in format {code, message, data}
final {"auth_token": authToken, "expired_at": expiredAt} = response["data"];
AuthenticatedHttpClient.getInstance().setAuthToken(authToken);
});
```
- Create request futures with support for path parameters.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"requestName" : "POST /api/submit/plan",
"requestNameWithColonParams" : "GET /api/plan/:id/details",
"requestNameWithBraceParams" : "GET /api/plan/{id}/details"
});
apiService.requestName().then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
apiService.requestNameWithColonParams({"id": 9527}).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
apiService.requestNameWithBraceParams({"id": 9527}).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- `UP` request uploads a file.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"uploadFile" : "UP /api/file"
});
String localPath = "/local/path/for/upload";
apiService.uploadFile({"file": localPath}, throttling: true).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- `DOWN` request downloads a file.
```dart
String url = "https://assets.xxx.com/path/of/file"; // or /static/file
var apiService = AuthenticatedHttpClient.getInstance().factory({
"download" : "DOWN $url"
});
void onReceiveProgress(int received, int total) {
print("Downloading Progress $received/$total");
}
String savePath = "/local/path/for/download";
// if Authorization is not required, set authenticate: false
apiService.download(null, savePath: savePath, authenticate: false, onReceiveProgress: onReceiveProgress).then((bytes) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- Mock requests are served from JSON files in the mockDirectory (defaulting to /lib/mock), which can be configured via AuthenticatedHttpClient.getInstance().init() and need to be declared under assets section in pubspec.yaml.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"mockRequest" : "MOCK POST /api/task/config",
});
// mock from _POST_api_task_config.json under mockDirectory /lib/mock
apiService.mockRequest().then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- Silent requests skip redirection for unauthorized responses or during maintenance.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"silentRequest" : "SILENT GET /api/message/check/unread"
});
// Even http status 401 won't redirect to login
apiService.silentRequest().then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- Throttling control, queue excess requests.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"request" : "SILENT POST /api/upload"
});
apiService.request(throttling: true).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- Every request would be marked with an unique id (say `requestId`) for tracking purpose, which also can be passed in as named argument.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"request" : "SILENT POST /api/upload"
});
String requestId = Uuid().v1();
print("gonna send request with unique id : $requestId");
apiService.request(requestId: requestId).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
```
- AuthenticatedHttpClient.all is a static function, like Promise.all, with a delay feature to prevent potential server concurrency issues.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"requestName" : "POST /api/submit/plan",
"requestNameWithParams" : "GET /api/plan/:id/details",
});
List futures = [apiService.requestName(), apiService.requestNameWithParams({"id": 9528})];
AuthenticatedHttpClient.all(futures, delayInMilliSecs: 350).then((List results){
print(results[0]); // response of No.1 request
print(results[1]); // response of No.2 request
});
```
## Steps for Usage in Dart
- Initialize a RouterHelper to manage when and how the authenticated HTTP client redirects to the login or maintenance route, if necessary.
```dart
import 'package:authenticated_http_client/router_helper.dart';
RouterHelper.init(
jump2LoginCallback: () { /* navigate to login route depends on routing library */ },
unAuthCode: "101|103"
);
```
`jump2LoginCallback` examples using different routing library
```dart
// FluroRouter example
BuildContext context; // keep current build context
function jump2LoginCallback() {
String? currentRoute = ModalRoute.of(context)?.settings.name;
if(currentRoute?.split("?").first == "/login") { return ; }
FluroRouter().navigateTo(context, "/login", clearStack: true);
}
```
```dart
// GoRouter example
BuildContext context; // keep current build context
function jump2LoginCallback() {
String? currentRoute = GoRouter.of(context).location;
if(currentRoute?.split("?").first == "/login") { return ; }
GoRouter(routes: []).go("/login");
}
```
- Implement the CustomHttpHeadersInterceptor required for initializing the AuthenticatedHttpClient later.
```dart
import 'package:authenticated_http_client/http_headers_interceptor.dart';
class Constants {
static String udid = "357292741221214";
static String appVersion = "1.0.1";
static String appBuildNumber = "1394";
static String systemCode = "e08f11c8-3b1c-4008-abba-045787e0b6c0";
}
class CustomHttpHeadersInterceptor extends HttpHeadersInterceptor {
@override
Map headersInterceptor(Map headers) {
headers["udid"] = Constants.udid;
headers["version"] = Constants.appVersion;
headers["system-code"] = Constants.systemCode;
return headers;
}
}
```
- Initialize an authenticated HTTP client that appends a token to the Authorization header for every subsequent AJAX request.
```dart
import 'package:authenticated_http_client/authenticated_http_client.dart';
AuthenticatedHttpClient.getInstance().init(
"https://api.company.com",
customHttpHeadersInterceptor: CustomHttpHeadersInterceptor()
);
```
- Ultimately, use any feature at your convenience.
```dart
var apiService = AuthenticatedHttpClient.getInstance().factory({
"login" : "POST /api/sign-in",
"requestName" : "POST /api/submit/plan",
"requestNameWithParams" : "GET /api/plan/:id/details", // or "GET /api/plan/{id}/details"
"mockRequest" : "MOCK POST /api/task/config", // mock from _post_api_task_config.json under mockDirectory /lib/mock
"silentRequest" : "SILENT GET /api/message/check/unread" // silent request won't jump when response met unauthorized or under maintenance
});
apiService.login({"username": "demo", "passwords": "test123"}).then((response) {
// response here in format {code, message, data}
final {"auth_token": authToken, "expired_at": expiredAt} = response["data"];
AuthenticatedHttpClient.getInstance().setAuthToken(authToken);
});
apiService.requestName().then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
apiService.requestNameWithParams({"id": 9527}).then((response) {/* success */}).catchError((e, stackTrace){ /* fail */ }).whenComplete((){ /* finally */ });
/// AuthenticatedHttpClient.all is a static function,similar to Promise.all,
/// which introduces a delay feature to prevent potential server concurrency issues
List futures = [apiService.requestName(), apiService.requestNameWithParams({"id": 9528})];
AuthenticatedHttpClient.all(futures, delayInMilliSecs: 350).then((results){
print(results['0']); // response of No.1 request
print(results['1']); // response of No.2 request
});
```
## Additional information
Feel free to file an issue if you have any problem.