Skip to content

Commit

Permalink
Merge pull request #43 from markgravity/chore/15-add-api-service
Browse files Browse the repository at this point in the history
[15] [Backend] Add API service
  • Loading branch information
markgravity authored May 7, 2021
2 parents d4bfd07 + 7a75d65 commit d61fdaa
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 0 deletions.
31 changes: 31 additions & 0 deletions lib/services/api/api_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
part of 'api_service.dart';

class ApiException implements Exception {
const ApiException({
required this.source,
required this.message,
required this.code,
});

static ApiException? fromHttpException(HttpException exception) {
if (exception.type != HttpExceptionType.response &&
exception.response?.data is! Map<String, dynamic>) {
return null;
}

final json = exception.response!.data as Map<String, dynamic>;
final source = json["errors"][0]["source"] as String;
final message = json["errors"][0]["detail"] as String;
final code = json["errors"][0]["code"] as String;

return ApiException(
source: source,
message: message,
code: code,
);
}

final String source;
final String message;
final String code;
}
5 changes: 5 additions & 0 deletions lib/services/api/api_params.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
part of 'api_service.dart';

abstract class ApiParams with Mappable {
//
}
92 changes: 92 additions & 0 deletions lib/services/api/api_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:survey/gen/configs.gen.dart';
import 'package:survey/services/http/http_service.dart';
import 'package:object_mapper/object_mapper.dart';
import 'package:survey/services/locator/locator_service.dart';

part 'api_exception.dart';

part 'api_params.dart';

part 'api_service_register.dart';

abstract class ApiService {
Future<T> call<T extends Mappable>({
required HttpMethod method,
String? baseUrl,
required String endPoint,
ApiParams? params,
bool requiresAuthentication = true,
String? token,
String? tokenType,
});

void configureGlobalBaseUrl(String? baseUrl);

void configureGlobalToken(String? token, String? tokenType);
}

class ApiServiceImpl implements ApiService {
static String? _baseUrl;
static String? _token;
static String _tokenType = "Bearer";
final HttpService _httpService = locator.get();

@override
Future<T> call<T extends Mappable>({
required HttpMethod method,
String? baseUrl,
required String endPoint,
ApiParams? params,
bool requiresAuthentication = true,
String? token,
String? tokenType,
}) async {
final String? finalBaseUrl = baseUrl ?? _baseUrl;
assert(finalBaseUrl != null);

final Map<String, dynamic> headers = {};

// Append token
final String? finalToken = token ?? _token;
if (requiresAuthentication && finalToken != null) {
final finalTokenType = tokenType ?? _tokenType;
headers["authorization"] = "$finalTokenType $finalToken";
}

final url = finalBaseUrl! + endPoint;
try {
final response = await _httpService.request(
method: method,
data: params?.toJson(),
url: url,
headers: headers,
) as Map<String, dynamic>;
return Mapper.fromJson(
response["data"]["attributes"] as Map<String, dynamic>)
.toObject<T>();
} on HttpException catch (e) {
throw ApiException.fromHttpException(e) ?? e;
}
}

/// Configures a default base url when [call] with `baseUrl` is null.
///
/// This value is stored in a static variable [_baseUrl] so it will be available in any
/// instance of [ApiServiceImpl], after set
@override
void configureGlobalBaseUrl(String? baseUrl) {
_baseUrl = baseUrl;
}

/// Configures a default token & tokenType when [call] with token or tokenType is null.
///
/// This value is stored in a static variable [_token], [_tokenType] so it will be available in any
/// instance of [ApiServiceImpl], after set
@override
void configureGlobalToken(String? token, String? tokenType) {
_token = token;
if (tokenType != null) {
_tokenType = tokenType;
}
}
}
9 changes: 9 additions & 0 deletions lib/services/api/api_service_register.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
part of 'api_service.dart';

class ApiServiceRegister {
final ApiService _apiService = locator.get();
ApiServiceRegister() {
Mappable.factories = Configs.factories;
_apiService.configureGlobalBaseUrl(Configs.app.api.baseUrl);
}
}
1 change: 1 addition & 0 deletions lib/services/locator/locator_service.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:get_it/get_it.dart';
import 'package:survey/services/api/api_service.dart';
import 'package:survey/services/http/http_service.dart';

part 'locator_service_register.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/services/locator/locator_service_register.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ part of 'locator_service.dart';
class LocatorServiceRegister {
LocatorServiceRegister() {
locator.registerFactory<HttpService>(() => HttpServiceImpl());
locator.registerFactory<ApiService>(() => ApiServiceImpl());
}
}

0 comments on commit d61fdaa

Please sign in to comment.