Skip to content
This repository has been archived by the owner on Jan 9, 2024. It is now read-only.

refactor: api client #10

Merged
merged 5 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions lib/main_development.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ void main() {
() {
final apiClient = ApiClient(
baseUrl: 'http://development',
idTokenStream: const Stream.empty(),
refreshIdToken: () async => Future.value(),
);

return App(
Expand Down
2 changes: 0 additions & 2 deletions lib/main_production.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ void main() {
() {
final apiClient = ApiClient(
baseUrl: 'http://production',
idTokenStream: const Stream.empty(),
refreshIdToken: () async => Future.value(),
);

return App(
Expand Down
2 changes: 0 additions & 2 deletions packages/api_client/example/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import 'package:api_client/api_client.dart';
Future<void> main() async {
final apiClient = ApiClient(
baseUrl: 'http://development',
idTokenStream: const Stream.empty(),
refreshIdToken: () async => Future.value(),
);
final questionsResource = apiClient.questionsResource;
final answer = await questionsResource.getVertexResponse('random');
Expand Down
122 changes: 45 additions & 77 deletions packages/api_client/lib/src/api_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,81 +53,55 @@ typedef GetCall = Future<http.Response> Function(
});

/// {@template api_client}
/// Client to access the api
/// 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,
bool realApiEnabled = false,
}) : _base = Uri.parse(baseUrl),
_post = postCall,
_put = putCall,
_patch = patchCall,
_get = getCall,
_refreshIdToken = refreshIdToken {
_idTokenSubscription = idTokenStream.listen((idToken) {
_idToken = idToken;
});
}
_realApiEnabled = realApiEnabled;

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;
final bool _realApiEnabled;

Map<String, String> get _headers => {
if (_idToken != null) 'Authorization': 'Bearer $_idToken',
};
Map<String, String> get _headers => {};

/// Questions resource.
late final QuestionsResource questionsResource = const QuestionsResource();

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();
}
late final QuestionsResource questionsResource = QuestionsResource(
apiClient: this,
realApiEnabled: _realApiEnabled,
);

/// 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;
});
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].
Expand All @@ -136,52 +110,46 @@ class ApiClient {
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;
});
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;
});
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;
});
final response = await _get(
_base.replace(
path: path,
queryParameters: queryParameters,
),
headers: _headers,
);

return response;
}
}

Expand Down
5 changes: 4 additions & 1 deletion packages/api_client/lib/src/models/vertex_document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part 'vertex_document.g.dart';
/// {@template vertex_document}
/// Vertex document
/// {@endtemplate}
@JsonSerializable(createToJson: false)
@JsonSerializable()
class VertexDocument extends Equatable {
/// {@macro vertex_document}
const VertexDocument({
Expand All @@ -18,6 +18,9 @@ class VertexDocument extends Equatable {
factory VertexDocument.fromJson(Map<String, dynamic> json) =>
_$VertexDocumentFromJson(json);

/// Converts this object to a map in JSON format.
Map<String, dynamic> toJson() => _$VertexDocumentToJson(this);

/// Metadata.
final VertexMetadata metadata;

Expand Down
5 changes: 5 additions & 0 deletions packages/api_client/lib/src/models/vertex_document.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/api_client/lib/src/models/vertex_metadata.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part 'vertex_metadata.g.dart';
/// {@template vertex_metadata}
/// Vertex metadata inside a [VertexDocument]
/// {@endtemplate}
@JsonSerializable(createToJson: false)
@JsonSerializable()
class VertexMetadata extends Equatable {
/// {@macro vertex_metadata}
const VertexMetadata({
Expand All @@ -20,6 +20,9 @@ class VertexMetadata extends Equatable {
factory VertexMetadata.fromJson(Map<String, dynamic> json) =>
_$VertexMetadataFromJson(json);

/// Converts this object to a map in JSON format.
Map<String, dynamic> toJson() => _$VertexMetadataToJson(this);

/// Url
final String url;

Expand Down
7 changes: 7 additions & 0 deletions packages/api_client/lib/src/models/vertex_metadata.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/api_client/lib/src/models/vertex_response.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ part 'vertex_response.g.dart';
/// {@template vertex_response}
/// Vertex response
/// {@endtemplate}
@JsonSerializable(createToJson: false)
@JsonSerializable()
class VertexResponse extends Equatable {
/// {@macro vertex_response}

Expand All @@ -20,6 +20,9 @@ class VertexResponse extends Equatable {
factory VertexResponse.fromJson(Map<String, dynamic> json) =>
_$VertexResponseFromJson(json);

/// Converts this object to a map in JSON format.
Map<String, dynamic> toJson() => _$VertexResponseToJson(this);

/// Summary.
final String summary;

Expand Down
6 changes: 6 additions & 0 deletions packages/api_client/lib/src/models/vertex_response.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 43 additions & 8 deletions packages/api_client/lib/src/resources/questions_resource.dart
Original file line number Diff line number Diff line change
@@ -1,23 +1,58 @@
import 'dart:convert';
import 'dart:io';

import 'package:api_client/api_client.dart';
import 'package:cross_file/cross_file.dart';

/// {@template questions_resource}
/// An api resource to get response to question from the VERTEX api
/// {@endtemplate}
class QuestionsResource {
/// {@macro questions_resource}
const QuestionsResource();
const QuestionsResource({
required ApiClient apiClient,
bool realApiEnabled = false,
}) : _apiClient = apiClient,
_realApiEnabled = realApiEnabled;

/// Get /game/prompt/terms
final ApiClient _apiClient;
final bool _realApiEnabled;

/// Returns [VertexResponse] based on a query.
///
/// Returns a [List<String>].
Future<VertexResponse> getVertexResponse(String query) async {
const path = 'lib/src/resources/fake_response.json';
final fakeResponse = await File(path).readAsString();
String body;
if (_realApiEnabled) {
final response = await _apiClient.get(
// TODO(oscar): update with real API once is enabled
// and add possible failures.
'google.es',
queryParameters: {
'query': query,
},
);
if (response.statusCode != 200) {
throw ApiClientError(
'GET getVertexResponse with query=$query '
'returned status ${response.statusCode} '
'with the following response: "${response.body}"',
StackTrace.current,
);
}
body = response.body;
} else {
const path = 'lib/src/resources/fake_response.json';
body = await XFile(path).readAsString();
}

final json = jsonDecode(fakeResponse) as Map<String, dynamic>;
return VertexResponse.fromJson(json);
try {
final json = jsonDecode(body) as Map<String, dynamic>;
return VertexResponse.fromJson(json);
} catch (e) {
throw ApiClientError(
'GET getVertexResponse with query=$query '
'returned invalid response "$body"',
StackTrace.current,
);
}
}
}
1 change: 1 addition & 0 deletions packages/api_client/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ environment:
sdk: ">=3.1.0 <4.0.0"

dependencies:
cross_file: ^0.3.3+6
equatable: ^2.0.5
http: ^1.1.0
json_annotation: ^4.8.1
Expand Down
Loading