From df9801ada11d6a95159b43f250d3a2f630a1dfcc Mon Sep 17 00:00:00 2001 From: Klemen Tusar Date: Thu, 9 May 2024 08:59:09 +0100 Subject: [PATCH] :bookmark: release v8.0.0 (#609) # chopper ## 8.0.0 - Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) - Add per-request timeout ([#604](https://github.com/lejard-h/chopper/pull/604)) # chopper_generator ## 8.0.0 - Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) - Add per-request timeout ([#604](https://github.com/lejard-h/chopper/pull/604)) ## 3.0.0 - Require Chopper ^8.0.0 --------- Signed-off-by: dependabot[bot] Co-authored-by: Job Guldemeester --- chopper/CHANGELOG.md | 12 +- .../http_logging_interceptor.dart | 121 ++- chopper/pubspec.yaml | 4 +- .../test/http_logging_interceptor_test.dart | 910 +++++++++++++----- chopper_built_value/CHANGELOG.md | 2 +- chopper_built_value/pubspec.yaml | 4 +- chopper_generator/CHANGELOG.md | 11 +- chopper_generator/pubspec.yaml | 4 +- example/lib/built_value_resource.chopper.dart | 3 +- .../lib/json_decode_service.activator.g.dart | 2 +- example/lib/json_decode_service.vm.g.dart | 2 +- example/lib/json_decode_service.worker.g.dart | 9 +- example/lib/json_serializable.chopper.dart | 3 +- example/pubspec.yaml | 20 +- 14 files changed, 764 insertions(+), 343 deletions(-) diff --git a/chopper/CHANGELOG.md b/chopper/CHANGELOG.md index ff514d1b..84af67b0 100644 --- a/chopper/CHANGELOG.md +++ b/chopper/CHANGELOG.md @@ -1,12 +1,14 @@ # Changelog -## 8.0.0-rc.2 +## 8.0.0 - Add per-request timeout ([#604](https://github.com/lejard-h/chopper/pull/604)) - -## 8.0.0-rc.1 - -- Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) +- **BREAKING CHANGE**: + - Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) + - `RequestInterceptor` and Function `RequestInterceptor`s are removed + - `ResponseInterceptor` and Function `ResponseInterceptor`s are removed + - See [Migrating to 8.0.0](https://docs.google.com/document/d/e/2PACX-1vQFoUDisnSJBzzXCMaf53ffUD1Bvpu-1GZ_stzfaaCa0Xd3WKIegbd1mmavEQcMT6r6v8z02UqloKuC/pub) for more information and examples + - add `onlyErrors` option to `HttpLoggingInterceptor` ([#610](https://github.com/lejard-h/chopper/pull/610)) ## 7.4.0 diff --git a/chopper/lib/src/interceptors/http_logging_interceptor.dart b/chopper/lib/src/interceptors/http_logging_interceptor.dart index 95bb6b2c..d8f5ee0f 100644 --- a/chopper/lib/src/interceptors/http_logging_interceptor.dart +++ b/chopper/lib/src/interceptors/http_logging_interceptor.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:chopper/src/chain/chain.dart'; import 'package:chopper/src/chopper_log_record.dart'; import 'package:chopper/src/interceptors/interceptor.dart'; +import 'package:chopper/src/request.dart'; import 'package:chopper/src/response.dart'; import 'package:chopper/src/utils.dart'; import 'package:http/http.dart' as http; @@ -75,12 +76,16 @@ enum Level { @immutable class HttpLoggingInterceptor implements Interceptor { /// {@macro http_logging_interceptor} - HttpLoggingInterceptor({this.level = Level.body, Logger? logger}) - : _logger = logger ?? chopperLogger, + HttpLoggingInterceptor({ + this.level = Level.body, + this.onlyErrors = false, + Logger? logger, + }) : _logger = logger ?? chopperLogger, _logBody = level == Level.body, _logHeaders = level == Level.body || level == Level.headers; final Level level; + final bool onlyErrors; final Logger _logger; final bool _logBody; final bool _logHeaders; @@ -88,103 +93,131 @@ class HttpLoggingInterceptor implements Interceptor { @override FutureOr> intercept( Chain chain) async { - final request = chain.request; - if (level == Level.none) return chain.proceed(request); + final Request request = chain.request; + + final Stopwatch stopWatch = Stopwatch()..start(); + + final Response response = await chain.proceed(request); + + stopWatch.stop(); + + if (level == Level.none || (onlyErrors && response.statusCode < 400)) { + return response; + } + final http.BaseRequest baseRequest = await request.toBaseRequest(); - String startRequestMessage = - '--> ${baseRequest.method} ${baseRequest.url.toString()}'; - String bodyRequestMessage = ''; + final StringBuffer startRequestMessage = StringBuffer( + '--> ${baseRequest.method} ${baseRequest.url.toString()}', + ); + final StringBuffer bodyRequestMessage = StringBuffer(); if (baseRequest is http.Request) { if (baseRequest.body.isNotEmpty) { - bodyRequestMessage = baseRequest.body; + bodyRequestMessage.write(baseRequest.body); if (!_logHeaders) { - startRequestMessage += ' (${baseRequest.bodyBytes.length}-byte body)'; + startRequestMessage.write( + ' (${baseRequest.bodyBytes.length}-byte body)', + ); } } } // Always start on a new line _logger.info(ChopperLogRecord('', request: request)); - _logger.info(ChopperLogRecord(startRequestMessage, request: request)); + _logger.info( + ChopperLogRecord(startRequestMessage.toString(), request: request), + ); if (_logHeaders) { baseRequest.headers.forEach( - (k, v) => _logger.info(ChopperLogRecord('$k: $v', request: request)), + (String k, String v) => _logger.info( + ChopperLogRecord('$k: $v', request: request), + ), ); if (baseRequest.contentLength != null && baseRequest.headers['content-length'] == null) { - _logger.info(ChopperLogRecord( - 'content-length: ${baseRequest.contentLength}', - request: request, - )); + _logger.info( + ChopperLogRecord( + 'content-length: ${baseRequest.contentLength}', + request: request, + ), + ); } } if (_logBody && bodyRequestMessage.isNotEmpty) { _logger.info(ChopperLogRecord('', request: request)); - _logger.info(ChopperLogRecord(bodyRequestMessage, request: request)); + _logger.info( + ChopperLogRecord(bodyRequestMessage.toString(), request: request), + ); } if (_logHeaders || _logBody) { - _logger.info(ChopperLogRecord( - '--> END ${baseRequest.method}', - request: request, - )); + _logger.info( + ChopperLogRecord('--> END ${baseRequest.method}', request: request), + ); } - final stopWatch = Stopwatch()..start(); - - final response = await chain.proceed(request); - - stopWatch.stop(); - if (level == Level.none) return response; - final baseResponse = response.base; + final http.BaseResponse baseResponse = response.base; - String bytes = ''; - String reasonPhrase = response.statusCode.toString(); - String bodyResponseMessage = ''; + final StringBuffer bytes = StringBuffer(); + final StringBuffer reasonPhrase = StringBuffer( + response.statusCode.toString(), + ); + final StringBuffer bodyResponseMessage = StringBuffer(); if (baseResponse is http.Response) { if (baseResponse.reasonPhrase != null) { - reasonPhrase += - ' ${baseResponse.reasonPhrase != reasonPhrase ? baseResponse.reasonPhrase : ''}'; + if (baseResponse.reasonPhrase != reasonPhrase.toString()) { + reasonPhrase.write(' ${baseResponse.reasonPhrase}'); + } } if (baseResponse.body.isNotEmpty) { - bodyResponseMessage = baseResponse.body; + bodyResponseMessage.write(baseResponse.body); if (!_logBody && !_logHeaders) { - bytes = ', ${response.bodyBytes.length}-byte body'; + bytes.write(', ${response.bodyBytes.length}-byte body'); } } } // Always start on a new line _logger.info(ChopperLogRecord('', response: response)); - _logger.info(ChopperLogRecord( - '<-- $reasonPhrase ${baseResponse.request?.method} ${baseResponse.request?.url.toString()} (${stopWatch.elapsedMilliseconds}ms$bytes)', - response: response, - )); + _logger.info( + ChopperLogRecord( + '<-- $reasonPhrase ${baseResponse.request?.method} ${baseResponse.request?.url.toString()} (${stopWatch.elapsedMilliseconds}ms$bytes)', + response: response, + ), + ); if (_logHeaders) { baseResponse.headers.forEach( - (k, v) => _logger.info(ChopperLogRecord('$k: $v', response: response)), + (String k, String v) => _logger.info( + ChopperLogRecord('$k: $v', response: response), + ), ); if (baseResponse.contentLength != null && baseResponse.headers['content-length'] == null) { - _logger.info(ChopperLogRecord( - 'content-length: ${baseResponse.contentLength}', - response: response, - )); + _logger.info( + ChopperLogRecord( + 'content-length: ${baseResponse.contentLength}', + response: response, + ), + ); } } if (_logBody && bodyResponseMessage.isNotEmpty) { _logger.info(ChopperLogRecord('', response: response)); - _logger.info(ChopperLogRecord(bodyResponseMessage, response: response)); + _logger.info( + ChopperLogRecord( + bodyResponseMessage.toString(), + response: response, + ), + ); } if (_logBody || _logHeaders) { diff --git a/chopper/pubspec.yaml b/chopper/pubspec.yaml index 77e41808..f71cfdbb 100644 --- a/chopper/pubspec.yaml +++ b/chopper/pubspec.yaml @@ -1,6 +1,6 @@ name: chopper description: Chopper is an http client generator using source_gen, inspired by Retrofit -version: 8.0.0-rc.2 +version: 8.0.0 documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper @@ -26,7 +26,7 @@ dev_dependencies: lints: ^3.0.0 test: ^1.25.4 transparent_image: ^2.0.1 - chopper_generator: ">=8.0.0-rc.1 <9.0.0" # Will be replaced with ^8.0.0 once released + chopper_generator: ">=8.0.0-rc.2 <9.0.0" # will be replaced by ^8.0.0 in the next release dependency_overrides: chopper_generator: diff --git a/chopper/test/http_logging_interceptor_test.dart b/chopper/test/http_logging_interceptor_test.dart index b2ba8aaa..22dc5799 100644 --- a/chopper/test/http_logging_interceptor_test.dart +++ b/chopper/test/http_logging_interceptor_test.dart @@ -8,7 +8,7 @@ import 'package:test/test.dart'; import 'helpers/fake_chain.dart'; void main() { - final fakeRequest = Request( + final Request fakeRequest = Request( 'POST', Uri.parse('/'), Uri.parse('base'), @@ -16,289 +16,671 @@ void main() { headers: {'foo': 'bar'}, ); - group('http logging requests', () { - test('Http logger interceptor none level request', () async { - final logger = HttpLoggingInterceptor(level: Level.none); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest)); - - expect( - logs, - equals( - [], - ), - ); + group('standard', () { + group('http logging requests', () { + test('Http logger interceptor none level request', () async { + final logger = HttpLoggingInterceptor(level: Level.none); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + equals( + [], + ), + ); + }); + + test('Http logger interceptor basic level request', () async { + final logger = HttpLoggingInterceptor(level: Level.basic); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + containsAll( + [ + '', + '--> POST base/ (4-byte body)', + ], + ), + ); + }); + + test('Http logger interceptor basic level request', () async { + final logger = HttpLoggingInterceptor(level: Level.headers); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + containsAll( + [ + '', + '--> POST base/', + 'foo: bar', + 'content-type: text/plain; charset=utf-8', + 'content-length: 4', + '--> END POST', + ], + ), + ); + }); + + test('Http logger interceptor body level request', () async { + final logger = HttpLoggingInterceptor(level: Level.body); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + containsAll( + [ + '', + '--> POST base/', + 'foo: bar', + 'content-type: text/plain; charset=utf-8', + 'content-length: 4', + '', + 'test', + '--> END POST', + ], + ), + ); + }); }); - test('Http logger interceptor basic level request', () async { - final logger = HttpLoggingInterceptor(level: Level.basic); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest)); - - expect( - logs, - containsAll( - [ - '', - '--> POST base/ (4-byte body)', - ], - ), - ); - }); + group('http logging interceptor response logging', () { + late Response fakeResponse; - test('Http logger interceptor basic level request', () async { - final logger = HttpLoggingInterceptor(level: Level.headers); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest)); - - expect( - logs, - containsAll( - [ - '', - '--> POST base/', - 'foo: bar', - 'content-type: text/plain; charset=utf-8', - 'content-length: 4', - '--> END POST', - ], - ), - ); + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 200, + headers: {'foo': 'bar'}, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('Http logger interceptor none level response', () async { + final logger = HttpLoggingInterceptor(level: Level.none); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + equals( + [], + ), + ); + }); + + test('Http logger interceptor basic level response', () async { + final logger = HttpLoggingInterceptor(level: Level.basic); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 200 POST base/ (0ms, 16-byte body)', + ], + ), + ); + }); + + test('Http logger interceptor headers level response', () async { + final logger = HttpLoggingInterceptor(level: Level.headers); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 200 POST base/ (0ms)', + 'foo: bar', + 'content-length: 16', + '<-- END HTTP', + ], + ), + ); + }); + + test('Http logger interceptor body level response', () async { + final logger = HttpLoggingInterceptor(level: Level.body); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 200 POST base/ (0ms)', + 'foo: bar', + 'content-length: 16', + '', + 'responseBodyBase', + '<-- END HTTP', + ], + ), + ); + }); }); - test('Http logger interceptor body level request', () async { - final logger = HttpLoggingInterceptor(level: Level.body); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest)); - - expect( - logs, - containsAll( - [ - '', - '--> POST base/', - 'foo: bar', - 'content-type: text/plain; charset=utf-8', - 'content-length: 4', - '', - 'test', - '--> END POST', - ], - ), - ); + group('headers content-length not overridden', () { + late Response fakeResponse; + + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 200, + headers: { + 'foo': 'bar', + 'content-length': '42', + }, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('request header level content-length', () async { + final logger = HttpLoggingInterceptor(level: Level.headers); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect( + logs, + containsAll( + [ + '', + '--> POST base/', + 'foo: bar', + 'content-length: 42', + 'content-type: text/plain; charset=utf-8', + '--> END POST', + ], + ), + ); + }); + + test('request body level content-length', () async { + final logger = HttpLoggingInterceptor(level: Level.body); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect( + logs, + containsAll( + [ + '', + '--> POST base/', + 'foo: bar', + 'content-length: 42', + 'content-type: text/plain; charset=utf-8', + '', + 'test', + '--> END POST', + ], + ), + ); + }); + + test('response header level content-length', () async { + final logger = HttpLoggingInterceptor(level: Level.headers); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 200 POST base/ (0ms)', + 'foo: bar', + 'content-length: 42', + '<-- END HTTP', + ], + ), + ); + }); + test('response body level content-length', () async { + final logger = HttpLoggingInterceptor(level: Level.body); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 200 POST base/ (0ms)', + 'foo: bar', + 'content-length: 42', + '', + 'responseBodyBase', + '<-- END HTTP', + ], + ), + ); + }); }); }); - group('http logging interceptor response logging', () { - late Response fakeResponse; - - setUp(() async { - fakeResponse = Response( - http.Response( - 'responseBodyBase', - 200, - headers: {'foo': 'bar'}, - request: await fakeRequest.toBaseRequest(), - ), - 'responseBody', - ); - }); + group('only errors', () { + group('http logging requests', () { + test('Http logger interceptor none level request', () async { + final logger = + HttpLoggingInterceptor(level: Level.none, onlyErrors: true); - test('Http logger interceptor none level response', () async { - final logger = HttpLoggingInterceptor(level: Level.none); + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest)); + expect(logs, equals([])); + }); - expect( - logs, - equals( - [], - ), - ); - }); + test('Http logger interceptor basic level request', () async { + final logger = + HttpLoggingInterceptor(level: Level.basic, onlyErrors: true); - test('Http logger interceptor basic level response', () async { - final logger = HttpLoggingInterceptor(level: Level.basic); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); - - expect( - logs, - containsAll( - [ - '', - '<-- 200 POST base/ (0ms, 16-byte body)', - ], - ), - ); - }); + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); - test('Http logger interceptor headers level response', () async { - final logger = HttpLoggingInterceptor(level: Level.headers); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); - - expect( - logs, - containsAll( - [ - '', - '<-- 200 POST base/ (0ms)', - 'foo: bar', - 'content-length: 16', - '<-- END HTTP', - ], - ), - ); - }); + expect(logs, equals([])); + }); - test('Http logger interceptor body level response', () async { - final logger = HttpLoggingInterceptor(level: Level.body); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); - - expect( - logs, - containsAll( - [ - '', - '<-- 200 POST base/ (0ms)', - 'foo: bar', - 'content-length: 16', - '', - 'responseBodyBase', - '<-- END HTTP', - ], - ), - ); - }); - }); + test('Http logger interceptor basic level request', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); - group('headers content-length not overridden', () { - late Response fakeResponse; - - setUp(() async { - fakeResponse = Response( - http.Response( - 'responseBodyBase', - 200, - headers: { - 'foo': 'bar', - 'content-length': '42', - }, - request: await fakeRequest.toBaseRequest(), - ), - 'responseBody', - ); - }); + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); - test('request header level content-length', () async { - final logger = HttpLoggingInterceptor(level: Level.headers); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - - await logger.intercept(FakeChain(fakeRequest.copyWith( - headers: {...fakeRequest.headers, 'content-length': '42'}))); - - expect( - logs, - containsAll( - [ - '', - '--> POST base/', - 'foo: bar', - 'content-length: 42', - 'content-type: text/plain; charset=utf-8', - '--> END POST', - ], - ), - ); - }); + expect(logs, equals([])); + }); - test('request body level content-length', () async { - final logger = HttpLoggingInterceptor(level: Level.body); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - - await logger.intercept(FakeChain(fakeRequest.copyWith( - headers: {...fakeRequest.headers, 'content-length': '42'}))); - - expect( - logs, - containsAll( - [ - '', - '--> POST base/', - 'foo: bar', - 'content-length: 42', - 'content-type: text/plain; charset=utf-8', - '', - 'test', - '--> END POST', - ], - ), - ); + test('Http logger interceptor body level request', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect(logs, equals([])); + }); }); - test('response header level content-length', () async { - final logger = HttpLoggingInterceptor(level: Level.headers); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); - - expect( - logs, - containsAll( - [ - '', - '<-- 200 POST base/ (0ms)', - 'foo: bar', - 'content-length: 42', - '<-- END HTTP', - ], - ), - ); + group('HTTP 200', () { + group('http logging interceptor response logging', () { + late Response fakeResponse; + + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 200, + headers: {'foo': 'bar'}, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('Http logger interceptor none level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.none, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + equals( + [], + ), + ); + }); + + test('Http logger interceptor basic level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.basic, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect(logs, equals([])); + }); + + test('Http logger interceptor headers level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect(logs, equals([])); + }); + + test('Http logger interceptor body level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect(logs, equals([])); + }); + }); + + group('headers content-length not overridden', () { + late Response fakeResponse; + + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 200, + headers: { + 'foo': 'bar', + 'content-length': '42', + }, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('request header level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect(logs, equals([])); + }); + + test('request body level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect(logs, equals([])); + }); + + test('response header level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect(logs, equals([])); + }); + test('response body level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect(logs, equals([])); + }); + }); }); - test('response body level content-length', () async { - final logger = HttpLoggingInterceptor(level: Level.body); - - final logs = []; - chopperLogger.onRecord.listen((r) => logs.add(r.message)); - await logger.intercept(FakeChain(fakeRequest, response: fakeResponse)); - - expect( - logs, - containsAll( - [ - '', - '<-- 200 POST base/ (0ms)', - 'foo: bar', - 'content-length: 42', - '', - 'responseBodyBase', - '<-- END HTTP', - ], - ), - ); + + group('HTTP 400', () { + group('http logging interceptor response logging', () { + late Response fakeResponse; + + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 400, + headers: {'foo': 'bar'}, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('Http logger interceptor none level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.none, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger.intercept(FakeChain(fakeRequest)); + + expect( + logs, + equals( + [], + ), + ); + }); + + test('Http logger interceptor basic level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.basic, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 400 POST base/ (0ms, 16-byte body)', + ], + ), + ); + }); + + test('Http logger interceptor headers level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 400 POST base/ (0ms)', + 'foo: bar', + 'content-length: 16', + '<-- END HTTP', + ], + ), + ); + }); + + test('Http logger interceptor body level response', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 400 POST base/ (0ms)', + 'foo: bar', + 'content-length: 16', + '', + 'responseBodyBase', + '<-- END HTTP', + ], + ), + ); + }); + }); + + group('headers content-length not overridden', () { + late Response fakeResponse; + + setUp(() async { + fakeResponse = Response( + http.Response( + 'responseBodyBase', + 400, + headers: { + 'foo': 'bar', + 'content-length': '42', + }, + request: await fakeRequest.toBaseRequest(), + ), + 'responseBody', + ); + }); + + test('request header level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect(logs, equals([])); + }); + + test('request body level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + + await logger.intercept(FakeChain(fakeRequest.copyWith( + headers: {...fakeRequest.headers, 'content-length': '42'}))); + + expect(logs, equals([])); + }); + + test('response header level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.headers, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 400 POST base/ (0ms)', + 'foo: bar', + 'content-length: 42', + '<-- END HTTP', + ], + ), + ); + }); + test('response body level content-length', () async { + final logger = + HttpLoggingInterceptor(level: Level.body, onlyErrors: true); + + final logs = []; + chopperLogger.onRecord.listen((r) => logs.add(r.message)); + await logger + .intercept(FakeChain(fakeRequest, response: fakeResponse)); + + expect( + logs, + containsAll( + [ + '', + '<-- 400 POST base/ (0ms)', + 'foo: bar', + 'content-length: 42', + '', + 'responseBodyBase', + '<-- END HTTP', + ], + ), + ); + }); + }); }); }); } diff --git a/chopper_built_value/CHANGELOG.md b/chopper_built_value/CHANGELOG.md index 5a05485d..f0297951 100644 --- a/chopper_built_value/CHANGELOG.md +++ b/chopper_built_value/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 3.0.0-rc.1 +## 3.0.0 - Require Chopper ^8.0.0 diff --git a/chopper_built_value/pubspec.yaml b/chopper_built_value/pubspec.yaml index 6c8a60ba..d1303271 100644 --- a/chopper_built_value/pubspec.yaml +++ b/chopper_built_value/pubspec.yaml @@ -1,6 +1,6 @@ name: chopper_built_value description: A built_value based Converter for Chopper. -version: 3.0.0-rc.1 +version: 3.0.0 documentation: https://hadrien-lejard.gitbook.io/chopper/converters/built-value-converter repository: https://github.com/lejard-h/chopper @@ -10,7 +10,7 @@ environment: dependencies: built_value: ^8.9.2 built_collection: ^5.1.1 - chopper: ">=8.0.0-rc.1 <9.0.0" + chopper: ^8.0.0 http: ^1.1.0 dev_dependencies: diff --git a/chopper_generator/CHANGELOG.md b/chopper_generator/CHANGELOG.md index 43d7a709..c41e9fe1 100644 --- a/chopper_generator/CHANGELOG.md +++ b/chopper_generator/CHANGELOG.md @@ -1,12 +1,13 @@ # Changelog -## 8.0.0-rc.2 +## 8.0.0 - Add per-request timeout ([#604](https://github.com/lejard-h/chopper/pull/604)) - -## 8.0.0-rc.1 - -- Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) +- **BREAKING CHANGE**: + - Restructure interceptors ([#547](https://github.com/lejard-h/chopper/pull/547)) + - `RequestInterceptor` and Function `RequestInterceptor`s are removed + - `ResponseInterceptor` and Function `ResponseInterceptor`s are removed + - See [Migrating to 8.0.0](https://docs.google.com/document/d/e/2PACX-1vQFoUDisnSJBzzXCMaf53ffUD1Bvpu-1GZ_stzfaaCa0Xd3WKIegbd1mmavEQcMT6r6v8z02UqloKuC/pub) for more information and examples ## 7.4.0 diff --git a/chopper_generator/pubspec.yaml b/chopper_generator/pubspec.yaml index 394c6a30..92e14816 100644 --- a/chopper_generator/pubspec.yaml +++ b/chopper_generator/pubspec.yaml @@ -1,6 +1,6 @@ name: chopper_generator description: Chopper is an http client generator using source_gen, inspired by Retrofit -version: 8.0.0-rc.2 +version: 8.0.0 documentation: https://hadrien-lejard.gitbook.io/chopper repository: https://github.com/lejard-h/chopper @@ -11,7 +11,7 @@ dependencies: analyzer: ^6.4.1 build: ^2.4.1 built_collection: ^5.1.1 - chopper: ">=8.0.0-rc.1 <9.0.0" # Will be replaced with ^8.0.0 once released + chopper: ^8.0.0 code_builder: ^4.10.0 dart_style: ^2.3.6 logging: ^1.2.0 diff --git a/example/lib/built_value_resource.chopper.dart b/example/lib/built_value_resource.chopper.dart index 32264219..01377685 100644 --- a/example/lib/built_value_resource.chopper.dart +++ b/example/lib/built_value_resource.chopper.dart @@ -6,6 +6,7 @@ part of 'built_value_resource.dart'; // ChopperGenerator // ************************************************************************** +// coverage:ignore-file // ignore_for_file: type=lint final class _$MyService extends MyService { _$MyService([ChopperClient? client]) { @@ -14,7 +15,7 @@ final class _$MyService extends MyService { } @override - final definitionType = MyService; + final Type definitionType = MyService; @override Future> getResource(String id) { diff --git a/example/lib/json_decode_service.activator.g.dart b/example/lib/json_decode_service.activator.g.dart index 48ed6298..d7b57dda 100644 --- a/example/lib/json_decode_service.activator.g.dart +++ b/example/lib/json_decode_service.activator.g.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** -// Generator: WorkerGenerator 2.4.1 +// Generator: WorkerGenerator 2.4.2 // ************************************************************************** import 'json_decode_service.vm.g.dart'; diff --git a/example/lib/json_decode_service.vm.g.dart b/example/lib/json_decode_service.vm.g.dart index 09d73096..3e2fc437 100644 --- a/example/lib/json_decode_service.vm.g.dart +++ b/example/lib/json_decode_service.vm.g.dart @@ -1,7 +1,7 @@ // GENERATED CODE - DO NOT MODIFY BY HAND // ************************************************************************** -// Generator: WorkerGenerator 2.4.1 +// Generator: WorkerGenerator 2.4.2 // ************************************************************************** import 'package:squadron/squadron.dart'; diff --git a/example/lib/json_decode_service.worker.g.dart b/example/lib/json_decode_service.worker.g.dart index 18a33d72..2bf75a7b 100644 --- a/example/lib/json_decode_service.worker.g.dart +++ b/example/lib/json_decode_service.worker.g.dart @@ -3,7 +3,7 @@ part of 'json_decode_service.dart'; // ************************************************************************** -// Generator: WorkerGenerator 2.4.1 +// Generator: WorkerGenerator 2.4.2 // ************************************************************************** /// WorkerService class for JsonDecodeService @@ -14,9 +14,10 @@ class _$JsonDecodeServiceWorkerService extends JsonDecodeService @override Map get operations => _operations; - late final Map _operations = { - _$jsonDecodeId: ($) => jsonDecode($.args[0]) - }; + late final Map _operations = + Map.unmodifiable({ + _$jsonDecodeId: ($) => jsonDecode($.args[0]), + }); static const int _$jsonDecodeId = 1; } diff --git a/example/lib/json_serializable.chopper.dart b/example/lib/json_serializable.chopper.dart index e6164985..07a9e4c1 100644 --- a/example/lib/json_serializable.chopper.dart +++ b/example/lib/json_serializable.chopper.dart @@ -6,6 +6,7 @@ part of 'json_serializable.dart'; // ChopperGenerator // ************************************************************************** +// coverage:ignore-file // ignore_for_file: type=lint final class _$MyService extends MyService { _$MyService([ChopperClient? client]) { @@ -14,7 +15,7 @@ final class _$MyService extends MyService { } @override - final definitionType = MyService; + final Type definitionType = MyService; @override Future> getResource(String id) { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 735d046c..df06f946 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,28 +1,28 @@ name: chopper_example description: Example usage of the Chopper package -version: 0.0.5 +version: 0.0.6 documentation: https://hadrien-lejard.gitbook.io/chopper/ #author: Hadrien Lejard environment: - sdk: '>=3.0.0 <4.0.0' + sdk: ^3.0.0 dependencies: chopper: - json_annotation: ^4.8.1 + json_annotation: ^4.9.0 built_value: - analyzer: ^5.13.0 + analyzer: ^6.4.1 http: ^1.1.0 built_collection: ^5.1.1 - squadron: ^5.1.3 + squadron: ^5.1.6 dev_dependencies: - build_runner: ^2.4.6 + build_runner: ^2.4.9 chopper_generator: - json_serializable: ^6.7.1 - built_value_generator: ^8.6.1 - lints: ^2.1.1 - squadron_builder: ^2.4.1 + json_serializable: ^6.8.0 + built_value_generator: ^8.9.2 + lints: ^3.0.0 + squadron_builder: ^2.4.5 dependency_overrides: chopper: