This repository has been archived by the owner on Jan 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
760 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
import 'package:api_client/api_client.dart'; | ||
import 'package:dash_ai_search/app/app.dart'; | ||
import 'package:dash_ai_search/bootstrap.dart'; | ||
|
||
void main() { | ||
bootstrap(() => const App()); | ||
bootstrap( | ||
() { | ||
final apiClient = ApiClient( | ||
baseUrl: 'http://localhost:8080', | ||
idTokenStream: const Stream.empty(), | ||
refreshIdToken: () async => Future.value(), | ||
); | ||
|
||
return App( | ||
apiClient: apiClient, | ||
); | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
import 'package:api_client/api_client.dart'; | ||
import 'package:dash_ai_search/app/app.dart'; | ||
import 'package:dash_ai_search/bootstrap.dart'; | ||
|
||
void main() { | ||
bootstrap(() => const App()); | ||
bootstrap( | ||
() { | ||
final apiClient = ApiClient( | ||
baseUrl: 'http://production', | ||
idTokenStream: const Stream.empty(), | ||
refreshIdToken: () async => Future.value(), | ||
); | ||
|
||
return App( | ||
apiClient: apiClient, | ||
); | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,19 @@ | ||
import 'package:api_client/api_client.dart'; | ||
import 'package:dash_ai_search/app/app.dart'; | ||
import 'package:dash_ai_search/bootstrap.dart'; | ||
|
||
void main() { | ||
bootstrap(() => const App()); | ||
bootstrap( | ||
() { | ||
final apiClient = ApiClient( | ||
baseUrl: 'http://staging', | ||
idTokenStream: const Stream.empty(), | ||
refreshIdToken: () async => Future.value(), | ||
); | ||
|
||
return App( | ||
apiClient: apiClient, | ||
); | ||
}, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# See https://www.dartlang.org/guides/libraries/private-files | ||
|
||
# Files and directories created by pub | ||
.dart_tool/ | ||
.packages | ||
build/ | ||
pubspec.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Api Client | ||
|
||
[![style: very good analysis][very_good_analysis_badge]][very_good_analysis_link] | ||
[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](https://github.com/felangel/mason) | ||
[![License: MIT][license_badge]][license_link] | ||
|
||
Client to access the api | ||
|
||
|
||
[license_badge]: https://img.shields.io/badge/license-MIT-blue.svg | ||
[license_link]: https://opensource.org/licenses/MIT | ||
[very_good_analysis_badge]: https://img.shields.io/badge/style-very_good_analysis-B22C89.svg | ||
[very_good_analysis_link]: https://pub.dev/packages/very_good_analysis |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include: package:very_good_analysis/analysis_options.5.1.0.yaml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
/// Client to access the api | ||
library api_client; | ||
|
||
export 'src/api_client.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
import 'dart:async'; | ||
import 'dart:io'; | ||
|
||
import 'package:http/http.dart' as http; | ||
|
||
/// {@template api_client_error} | ||
/// Error throw when accessing api failed. | ||
/// | ||
/// Check [cause] and [stackTrace] for specific details. | ||
/// {@endtemplate} | ||
class ApiClientError implements Exception { | ||
/// {@macro api_client_error} | ||
ApiClientError(this.cause, this.stackTrace); | ||
|
||
/// Error cause. | ||
final dynamic cause; | ||
|
||
/// The stack trace of the error. | ||
final StackTrace stackTrace; | ||
|
||
@override | ||
String toString() { | ||
return cause.toString(); | ||
} | ||
} | ||
|
||
/// Definition of a post call used by this client. | ||
typedef PostCall = Future<http.Response> Function( | ||
Uri, { | ||
Object? body, | ||
Map<String, String>? headers, | ||
}); | ||
|
||
/// Definition of a patch call used by this client. | ||
typedef PatchCall = Future<http.Response> Function( | ||
Uri, { | ||
Object? body, | ||
Map<String, String>? headers, | ||
}); | ||
|
||
/// Definition of a put call used by this client. | ||
typedef PutCall = Future<http.Response> Function( | ||
Uri, { | ||
Object? body, | ||
Map<String, String>? headers, | ||
}); | ||
|
||
/// Definition of a get call used by this client. | ||
typedef GetCall = Future<http.Response> Function( | ||
Uri, { | ||
Map<String, String>? headers, | ||
}); | ||
|
||
/// {@template api_client} | ||
/// Client to access the api | ||
/// {@endtemplate} | ||
class ApiClient { | ||
/// {@macro api_client} | ||
ApiClient({ | ||
required String baseUrl, | ||
required Stream<String?> idTokenStream, | ||
required Future<String?> Function() refreshIdToken, | ||
PostCall postCall = http.post, | ||
PutCall putCall = http.put, | ||
PatchCall patchCall = http.patch, | ||
GetCall getCall = http.get, | ||
}) : _base = Uri.parse(baseUrl), | ||
_post = postCall, | ||
_put = putCall, | ||
_patch = patchCall, | ||
_get = getCall, | ||
_refreshIdToken = refreshIdToken { | ||
_idTokenSubscription = idTokenStream.listen((idToken) { | ||
_idToken = idToken; | ||
}); | ||
} | ||
|
||
final Uri _base; | ||
final PostCall _post; | ||
final PostCall _put; | ||
final PatchCall _patch; | ||
final GetCall _get; | ||
final Future<String?> Function() _refreshIdToken; | ||
|
||
late final StreamSubscription<String?> _idTokenSubscription; | ||
String? _idToken; | ||
|
||
Map<String, String> get _headers => { | ||
if (_idToken != null) 'Authorization': 'Bearer $_idToken', | ||
}; | ||
|
||
Future<http.Response> _handleUnauthorized( | ||
Future<http.Response> Function() sendRequest, | ||
) async { | ||
final response = await sendRequest(); | ||
|
||
if (response.statusCode == HttpStatus.unauthorized) { | ||
_idToken = await _refreshIdToken(); | ||
return sendRequest(); | ||
} | ||
return response; | ||
} | ||
|
||
/// Dispose of resources used by this client. | ||
Future<void> dispose() async { | ||
await _idTokenSubscription.cancel(); | ||
} | ||
|
||
/// Sends a POST request to the specified [path] with the given [body]. | ||
Future<http.Response> post( | ||
String path, { | ||
Object? body, | ||
Map<String, String>? queryParameters, | ||
}) async { | ||
return _handleUnauthorized(() async { | ||
final response = await _post( | ||
_base.replace( | ||
path: path, | ||
queryParameters: queryParameters, | ||
), | ||
body: body, | ||
headers: _headers..addContentTypeJson(), | ||
); | ||
|
||
return response; | ||
}); | ||
} | ||
|
||
/// Sends a PATCH request to the specified [path] with the given [body]. | ||
Future<http.Response> patch( | ||
String path, { | ||
Object? body, | ||
Map<String, String>? queryParameters, | ||
}) async { | ||
return _handleUnauthorized(() async { | ||
final response = await _patch( | ||
_base.replace( | ||
path: path, | ||
queryParameters: queryParameters, | ||
), | ||
body: body, | ||
headers: _headers..addContentTypeJson(), | ||
); | ||
|
||
return response; | ||
}); | ||
} | ||
|
||
/// Sends a PUT request to the specified [path] with the given [body]. | ||
Future<http.Response> put( | ||
String path, { | ||
Object? body, | ||
}) async { | ||
return _handleUnauthorized(() async { | ||
final response = await _put( | ||
_base.replace(path: path), | ||
body: body, | ||
headers: _headers..addContentTypeJson(), | ||
); | ||
|
||
return response; | ||
}); | ||
} | ||
|
||
/// Sends a GET request to the specified [path]. | ||
Future<http.Response> get( | ||
String path, { | ||
Map<String, String>? queryParameters, | ||
}) async { | ||
return _handleUnauthorized(() async { | ||
final response = await _get( | ||
_base.replace( | ||
path: path, | ||
queryParameters: queryParameters, | ||
), | ||
headers: _headers, | ||
); | ||
|
||
return response; | ||
}); | ||
} | ||
} | ||
|
||
extension on Map<String, String> { | ||
void addContentTypeJson() { | ||
addAll({HttpHeaders.contentTypeHeader: ContentType.json.value}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
name: api_client | ||
description: Client to access the api | ||
version: 0.1.0+1 | ||
publish_to: none | ||
|
||
environment: | ||
sdk: ">=3.0.0 <4.0.0" | ||
|
||
dev_dependencies: | ||
mocktail: ^1.0.0 | ||
test: ^1.19.2 | ||
very_good_analysis: ^5.1.0 | ||
|
||
dependencies: | ||
http: ^1.1.0 |
Oops, something went wrong.