Skip to content

Commit

Permalink
✨ Feature: Omit Response in service (#545)
Browse files Browse the repository at this point in the history
  • Loading branch information
Guldem authored Jan 5, 2024
1 parent 4ba5a83 commit 6420778
Show file tree
Hide file tree
Showing 21 changed files with 2,125 additions and 85 deletions.
13 changes: 13 additions & 0 deletions chopper/lib/src/chopper_http_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import 'package:chopper/src/response.dart';

/// An exception thrown when a [Response] is unsuccessful < 200 or > 300.
class ChopperHttpException implements Exception {
ChopperHttpException(this.response);

final Response response;

@override
String toString() {
return 'Could not fetch the response for ${response.base.request}. Status code: ${response.statusCode}, error: ${response.error}';
}
}
15 changes: 15 additions & 0 deletions chopper/lib/src/response.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:typed_data';

import 'package:chopper/src/chopper_http_exception.dart';
import 'package:equatable/equatable.dart' show EquatableMixin;
import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
Expand Down Expand Up @@ -76,6 +77,20 @@ base class Response<BodyType> with EquatableMixin {
}
}

/// Returns the response body if [Response] [isSuccessful] and [body] is not null.
/// Otherwise it throws an [HttpException] with the response status code and error object.
/// If the error object is an [Exception], it will be thrown instead.
BodyType get bodyOrThrow {
if (isSuccessful && body != null) {
return body!;
} else {
if (error is Exception) {
throw error!;
}
throw ChopperHttpException(this);
}
}

@override
List<Object?> get props => [
base,
Expand Down
49 changes: 0 additions & 49 deletions chopper/test/base_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'package:http/testing.dart';
import 'package:test/test.dart';
import 'package:transparent_image/transparent_image.dart';

import 'fixtures/error_fixtures.dart';
import 'fixtures/example_enum.dart';
import 'test_service.dart';
import 'test_service_base_url.dart';
Expand Down Expand Up @@ -1650,52 +1649,4 @@ void main() {

httpClient.close();
});

group('Response error casting test', () {
test('Response is succesfull, [returns null]', () {
final base = http.Response('Foobar', 200);

final response = Response(base, 'Foobar');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test('Response is unsuccessful and has no error object, [returns null]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, '');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test(
'Response is unsuccessful and has error object of different type, [returns null]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, '', error: 'Foobar');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test(
'Response is unsuccessful and has error object of specified type, [returns error as ErrorType]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, 'Foobar', error: FooErrorType());

final result = response.errorWhereType<FooErrorType>();

expect(result, isNotNull);
expect(result, isA<FooErrorType>());
});
});
}
21 changes: 21 additions & 0 deletions chopper/test/chopper_http_exception_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:chopper/src/chopper_http_exception.dart';
import 'package:chopper/src/response.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';

void main() {
test('ChopperHttpException toString prints available information', () {
final request = http.Request('GET', Uri.parse('http://localhost:8000'));
final base = http.Response('Foobar', 400, request: request);
final response = Response(base, 'Foobar', error: 'FooError');

final exception = ChopperHttpException(response);

final result = exception.toString();

expect(
result,
'Could not fetch the response for GET http://localhost:8000. Status code: 400, error: FooError',
);
});
}
1 change: 1 addition & 0 deletions chopper/test/ensure_build_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void main() {
gitDiffPathArguments: [
'test/test_service.chopper.dart',
'test/test_service_variable.chopper.dart',
'test/test_without_response_service.chopper.dart',
'test/test_service_base_url.chopper.dart',
],
);
Expand Down
114 changes: 114 additions & 0 deletions chopper/test/response_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import 'package:chopper/src/chopper_http_exception.dart';
import 'package:chopper/src/response.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';

import 'fixtures/error_fixtures.dart';

void main() {
group('Response error casting test', () {
test('Response is succesfull, [returns null]', () {
final base = http.Response('Foobar', 200);

final response = Response(base, 'Foobar');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test('Response is unsuccessful and has no error object, [returns null]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, '');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test(
'Response is unsuccessful and has error object of different type, [returns null]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, '', error: 'Foobar');

final result = response.errorWhereType<FooErrorType>();

expect(result, isNull);
});

test(
'Response is unsuccessful and has error object of specified type, [returns error as ErrorType]',
() {
final base = http.Response('Foobar', 400);

final response = Response(base, 'Foobar', error: FooErrorType());

final result = response.errorWhereType<FooErrorType>();

expect(result, isNotNull);
expect(result, isA<FooErrorType>());
});
});

group('bodyOrThrow tests', () {
test('Response is successful and has body, [bodyOrThrow returns body]', () {
final base = http.Response('Foobar', 200);
final response = Response(base, {'Foo': 'Bar'});

final result = response.bodyOrThrow;

expect(result, isNotNull);
expect(result, {'Foo': 'Bar'});
});

test(
'Response is unsuccessful and has Exception as error, [bodyOrThrow throws error]',
() {
final base = http.Response('Foobar', 400);
final response = Response(base, '', error: Exception('Error occurred'));

expect(() => response.bodyOrThrow, throwsA(isA<Exception>()));
});

test(
'Response is unsuccessful and has non-exception object as error, [bodyOrThrow throws error]',
() {
final base = http.Response('Foobar', 400);
final response = Response(base, '', error: 'Error occurred');

expect(() => response.bodyOrThrow, throwsA(isA<ChopperHttpException>()));
});

test(
'Response is unsuccessful and has no error, [bodyOrThrow throws ChopperHttpException]',
() {
final base = http.Response('Foobar', 400);
final response = Response(base, '');

expect(() => response.bodyOrThrow, throwsA(isA<ChopperHttpException>()));
});

test(
'Response is successful and has no body, [bodyOrThrow throws ChopperHttpException]',
() {
final base = http.Response('Foobar', 200);
final Response<String> response = Response(base, null);

expect(() => response.bodyOrThrow, throwsA(isA<ChopperHttpException>()));
});

test('Response is successful and has void body, [bodyOrThrow returns void]',
() {
final base = http.Response('Foobar', 200);
// Ignoring void checks for testing purposes
//ignore: void_checks
final Response<void> response = Response(base, '');

expect(() => response.bodyOrThrow, returnsNormally);
});
});
}
4 changes: 2 additions & 2 deletions chopper/test/test_service.chopper.dart

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

2 changes: 1 addition & 1 deletion chopper/test/test_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ abstract class HttpTestService extends ChopperService {
});

@Get(path: 'https://test.com')
Future fullUrl();
Future<Response> fullUrl();

@Get(path: '/list/string')
Future<Response<List<String>>> listString();
Expand Down
4 changes: 2 additions & 2 deletions chopper/test/test_service_variable.chopper.dart

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

2 changes: 1 addition & 1 deletion chopper/test/test_service_variable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ abstract class HttpTestServiceVariable extends ChopperService {
});

@Get(path: 'https://test.com')
Future fullUrl();
Future<Response> fullUrl();

@Get(path: '/list/string')
Future<Response<List<String>>> listString();
Expand Down
Loading

0 comments on commit 6420778

Please sign in to comment.