From 763558b3a1d223ed53b9501a538af6752dc0017d Mon Sep 17 00:00:00 2001 From: Mihail Date: Tue, 9 May 2023 11:49:32 +0200 Subject: [PATCH] Moved rest client to packages --- packages/rest_client/.gitignore | 7 ++ packages/rest_client/analysis_options.yaml | 1 + packages/rest_client/lib/rest_client.dart | 5 ++ .../lib/src}/exception/network_exception.dart | 4 -- packages/rest_client/lib/src/rest_client.dart | 42 ++++++++++++ .../rest_client/lib/src/rest_client_base.dart | 35 +++++----- packages/rest_client/pubspec.yaml | 18 +++++ .../rest_client/test}/rest_client_test.dart | 66 ++++++++++--------- pubspec.yaml | 3 + 9 files changed, 128 insertions(+), 53 deletions(-) create mode 100644 packages/rest_client/.gitignore create mode 100644 packages/rest_client/analysis_options.yaml create mode 100644 packages/rest_client/lib/rest_client.dart rename {lib/src/core/utils => packages/rest_client/lib/src}/exception/network_exception.dart (88%) create mode 100644 packages/rest_client/lib/src/rest_client.dart rename lib/src/core/data/rest_client.dart => packages/rest_client/lib/src/rest_client_base.dart (89%) create mode 100644 packages/rest_client/pubspec.yaml rename {test/unit => packages/rest_client/test}/rest_client_test.dart (88%) diff --git a/packages/rest_client/.gitignore b/packages/rest_client/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/rest_client/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/rest_client/analysis_options.yaml b/packages/rest_client/analysis_options.yaml new file mode 100644 index 0000000..7b43fa7 --- /dev/null +++ b/packages/rest_client/analysis_options.yaml @@ -0,0 +1 @@ +include: package:sizzle_lints/sizzle_lints.yaml \ No newline at end of file diff --git a/packages/rest_client/lib/rest_client.dart b/packages/rest_client/lib/rest_client.dart new file mode 100644 index 0000000..5f00b0d --- /dev/null +++ b/packages/rest_client/lib/rest_client.dart @@ -0,0 +1,5 @@ +library rest_client; + +export 'src/rest_client_base.dart'; +export 'src/exception/network_exception.dart'; +export 'src/rest_client.dart'; diff --git a/lib/src/core/utils/exception/network_exception.dart b/packages/rest_client/lib/src/exception/network_exception.dart similarity index 88% rename from lib/src/core/utils/exception/network_exception.dart rename to packages/rest_client/lib/src/exception/network_exception.dart index 90f8a57..96a1cf1 100644 --- a/lib/src/core/utils/exception/network_exception.dart +++ b/packages/rest_client/lib/src/exception/network_exception.dart @@ -1,12 +1,9 @@ import 'package:meta/meta.dart'; -import 'package:sizzle_starter/src/core/utils/annotation.dart'; @immutable -@exception abstract class NetworkException implements Exception {} @immutable -@exception class RestClientException implements NetworkException { const RestClientException({ this.message, @@ -21,7 +18,6 @@ class RestClientException implements NetworkException { } @immutable -@exception class InternalServerException implements NetworkException { const InternalServerException({ this.message, diff --git a/packages/rest_client/lib/src/rest_client.dart b/packages/rest_client/lib/src/rest_client.dart new file mode 100644 index 0000000..8705e08 --- /dev/null +++ b/packages/rest_client/lib/src/rest_client.dart @@ -0,0 +1,42 @@ +import 'package:http/http.dart' as http; +import 'package:rest_client/src/rest_client_base.dart'; + +abstract class RestClient { + factory RestClient({ + required String baseUrl, + http.Client? client, + }) = RestClientBase; + + Future> get( + String path, { + Map? headers, + Map? queryParams, + }); + + Future> post( + String path, { + required Map body, + Map? headers, + Map? queryParams, + }); + + Future> put( + String path, { + required Map body, + Map? headers, + Map? queryParams, + }); + + Future> delete( + String path, { + Map? headers, + Map? queryParams, + }); + + Future> patch( + String path, { + required Map body, + Map? headers, + Map? queryParams, + }); +} diff --git a/lib/src/core/data/rest_client.dart b/packages/rest_client/lib/src/rest_client_base.dart similarity index 89% rename from lib/src/core/data/rest_client.dart rename to packages/rest_client/lib/src/rest_client_base.dart index 663533a..facdc11 100644 --- a/lib/src/core/data/rest_client.dart +++ b/packages/rest_client/lib/src/rest_client_base.dart @@ -3,12 +3,12 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; -import 'package:platform_info/platform_info.dart' as info; -import 'package:sizzle_starter/src/core/utils/exception/network_exception.dart'; +import 'package:rest_client/src/exception/network_exception.dart'; +import 'package:rest_client/src/rest_client.dart'; @immutable -class RestClient { - RestClient({ +class RestClientBase implements RestClient { + RestClientBase({ required String baseUrl, http.Client? client, }) : _client = client ?? http.Client(), @@ -17,6 +17,7 @@ class RestClient { final Uri _baseUri; final http.Client _client; + @override Future> get( String path, { Map? headers, @@ -29,6 +30,7 @@ class RestClient { queryParams: queryParams, ); + @override Future> post( String path, { required Map body, @@ -42,6 +44,7 @@ class RestClient { queryParams: queryParams, ); + @override Future> put( String path, { required Map body, @@ -55,6 +58,7 @@ class RestClient { queryParams: queryParams, ); + @override Future> delete( String path, { Map? headers, @@ -67,6 +71,7 @@ class RestClient { queryParams: queryParams, ); + @override Future> patch( String path, { required Map body, @@ -89,7 +94,6 @@ class RestClient { }) async { try { final request = buildRequest( - baseUri: _baseUri, method: method, path: path, queryParams: queryParams, @@ -124,7 +128,7 @@ class RestClient { @protected @visibleForTesting - static List encodeBody( + List encodeBody( Map body, ) { try { @@ -139,7 +143,7 @@ class RestClient { @protected @visibleForTesting - static Map decodeResponse(http.Response response) { + Map decodeResponse(http.Response response) { final contentType = response.headers['content-type'] ?? response.headers['Content-Type']; if (contentType?.contains('application/json') ?? false) { final body = response.body; @@ -180,35 +184,33 @@ class RestClient { @protected @visibleForTesting - static Uri buildUri({ - required Uri baseUri, + Uri buildUri({ required String path, Map? queryParams, }) { final uri = Uri.tryParse(path); - if (uri == null) return baseUri; + if (uri == null) return _baseUri; final queryParameters = { - ...baseUri.queryParameters, + ..._baseUri.queryParameters, ...uri.queryParameters, ...?queryParams, }; - return baseUri.replace( - path: p.normalize(p.join(baseUri.path, uri.path)), + return _baseUri.replace( + path: p.normalize(p.join(_baseUri.path, uri.path)), queryParameters: queryParameters.isEmpty ? null : queryParameters, ); } @protected @visibleForTesting - static http.Request buildRequest({ - required Uri baseUri, + http.Request buildRequest({ required String method, required String path, Map? queryParams, Map? body, Map? headers, }) { - final uri = buildUri(path: path, baseUri: baseUri, queryParams: queryParams); + final uri = buildUri(path: path, queryParams: queryParams); final request = http.Request(method, uri); if (body != null) request.bodyBytes = encodeBody(body); request.headers.addAll({ @@ -223,7 +225,6 @@ class RestClient { // by the server even if it is HTTP/1.1+ 'Pragma': 'no-cache', 'Accept': 'application/json', - 'User-Agent': info.Platform.I.version, ...?headers?.map((key, value) => MapEntry(key, value.toString())), }); return request; diff --git a/packages/rest_client/pubspec.yaml b/packages/rest_client/pubspec.yaml new file mode 100644 index 0000000..6238ce6 --- /dev/null +++ b/packages/rest_client/pubspec.yaml @@ -0,0 +1,18 @@ +name: rest_client +description: A starting point for Dart libraries or applications. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: '>=2.19.6 <3.0.0' + +# dependencies: +# path: ^1.8.0 + +dev_dependencies: + sizzle_lints: ^1.0.10 + test: ^1.21.0 +dependencies: + http: ^0.13.6 + meta: ^1.8.0 + path: ^1.8.0 diff --git a/test/unit/rest_client_test.dart b/packages/rest_client/test/rest_client_test.dart similarity index 88% rename from test/unit/rest_client_test.dart rename to packages/rest_client/test/rest_client_test.dart index ed6ee95..a166217 100644 --- a/test/unit/rest_client_test.dart +++ b/packages/rest_client/test/rest_client_test.dart @@ -1,25 +1,37 @@ import 'dart:convert'; -import 'package:flutter_test/flutter_test.dart'; import 'package:http/http.dart' as http; import 'package:http/testing.dart'; -import 'package:sizzle_starter/src/core/data/rest_client.dart'; -import 'package:sizzle_starter/src/core/utils/exception/network_exception.dart'; +import 'package:rest_client/rest_client.dart'; +import 'package:test/test.dart'; void main() { group( - 'RestClient >', + 'RestClientImpl >', () { + late final Uri baseUri; + late final RestClientBase baseClient; + setUpAll( + () { + baseUri = Uri.parse('https://example.com'); + baseClient = RestClientBase( + baseUrl: baseUri.toString(), + client: MockClient( + (request) async => http.Response( + jsonEncode( + {'key': 'value'}, + ), + 200, + ), + ), + ); + }, + ); group('Build URI > ', () { - late final Uri baseUri; - setUpAll( - () => baseUri = Uri.parse('https://example.com'), - ); test( 'should build a valid URI with preceding slash', () { - final uri = RestClient.buildUri( - baseUri: baseUri, + final uri = baseClient.buildUri( path: '/path', ); expect(uri.toString(), 'https://example.com/path'); @@ -28,8 +40,7 @@ void main() { test( 'should build a valid URI without preceding slash', () { - final uri = RestClient.buildUri( - baseUri: baseUri, + final uri = baseClient.buildUri( path: 'path', ); expect(uri.toString(), 'https://example.com/path'); @@ -38,8 +49,7 @@ void main() { test( 'should build a valid URI with query parameters', () { - final uri = RestClient.buildUri( - baseUri: baseUri, + final uri = baseClient.buildUri( path: 'path?pathkey=pathvalue', queryParams: { 'key': 'value', @@ -53,15 +63,10 @@ void main() { ); }); group('Build request >', () { - late final Uri baseUri; - setUpAll( - () => baseUri = Uri.parse('https://example.com'), - ); test( 'should build a valid GET request', () { - final request = RestClient.buildRequest( - baseUri: baseUri, + final request = baseClient.buildRequest( path: 'path', method: 'GET', headers: { @@ -76,8 +81,7 @@ void main() { test( 'should build a valid POST request', () { - final request = RestClient.buildRequest( - baseUri: baseUri, + final request = baseClient.buildRequest( path: 'path', method: 'POST', headers: { @@ -96,8 +100,7 @@ void main() { test( 'should build a valid PUT request', () { - final request = RestClient.buildRequest( - baseUri: baseUri, + final request = baseClient.buildRequest( path: 'path', method: 'PUT', headers: { @@ -116,8 +119,7 @@ void main() { test( 'should build a valid DELETE request', () { - final request = RestClient.buildRequest( - baseUri: baseUri, + final request = baseClient.buildRequest( path: 'path', method: 'DELETE', headers: { @@ -142,7 +144,7 @@ void main() { }, ); expect( - () => RestClient.decodeResponse(response), + () => baseClient.decodeResponse(response), throwsA(isA()), reason: 'Should throw an exception for an invalid JSON response', ); @@ -159,7 +161,7 @@ void main() { }, ); expect( - () => RestClient.decodeResponse(response), + () => baseClient.decodeResponse(response), throwsA(isA()), ); }, @@ -175,7 +177,7 @@ void main() { }, ); expect( - () => RestClient.decodeResponse(response), + () => baseClient.decodeResponse(response), throwsA(isA()), ); }, @@ -189,7 +191,7 @@ void main() { }, ); expect( - () => RestClient.decodeResponse(response), + () => baseClient.decodeResponse(response), throwsA(isA()), ); }); @@ -202,7 +204,7 @@ void main() { }, ); expect( - () => RestClient.decodeResponse(response), + () => baseClient.decodeResponse(response), returnsNormally, ); }); @@ -212,7 +214,7 @@ void main() { final body = { 'key': 'value', }; - final encodedBody = RestClient.encodeBody(body); + final encodedBody = baseClient.encodeBody(body); expect(encodedBody, utf8.encode('{"key":"value"}')); }); }); diff --git a/pubspec.yaml b/pubspec.yaml index 6f814ad..ed46efc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -66,6 +66,9 @@ dependencies: platform_info: ^3.2.0 bloc_concurrency: ^0.2.1 + rest_client: + path: packages/rest_client + dev_dependencies: # Testing flutter_test: