diff --git a/CHANGELOG.md b/CHANGELOG.md index efa5192fe8..f9b5a21c82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Enhancements + +- Add `apiTarget` field to `SentryRequest` and `data` field to `SentryResponse` ([#1517](https://github.com/getsentry/sentry-dart/pull/1517)) + ### Dependencies - Bump Android SDK from v6.21.0 to v6.22.0 ([#1512](https://github.com/getsentry/sentry-dart/pull/1512)) diff --git a/dart/lib/src/protocol/sentry_request.dart b/dart/lib/src/protocol/sentry_request.dart index 42cb145fd5..9689c8a974 100644 --- a/dart/lib/src/protocol/sentry_request.dart +++ b/dart/lib/src/protocol/sentry_request.dart @@ -62,12 +62,20 @@ class SentryRequest { /// The fragment of the request URL. final String? fragment; + /// The API target/specification that made the request. + /// Values can be `graphql`, `rest`, etc. + /// + /// The data field should contain the request and response bodies based on + /// its target specification. + final String? apiTarget; + SentryRequest({ this.url, this.method, this.queryString, String? cookies, this.fragment, + this.apiTarget, dynamic data, Map? headers, Map? env, @@ -90,6 +98,7 @@ class SentryRequest { dynamic data, Map? headers, Map? env, + String? apiTarget, @Deprecated('Will be removed in v8. Use [data] instead') Map? other, }) { @@ -104,6 +113,7 @@ class SentryRequest { fragment: uri.fragment, // ignore: deprecated_member_use_from_same_package other: other, + apiTarget: apiTarget, ).sanitized(); } @@ -120,6 +130,7 @@ class SentryRequest { // ignore: deprecated_member_use_from_same_package other: json.containsKey('other') ? Map.from(json['other']) : null, fragment: json['fragment'], + apiTarget: json['api_target'], ); } @@ -136,6 +147,7 @@ class SentryRequest { // ignore: deprecated_member_use_from_same_package if (other.isNotEmpty) 'other': other, if (fragment != null) 'fragment': fragment, + if (apiTarget != null) 'api_target': apiTarget, }; } @@ -148,9 +160,10 @@ class SentryRequest { dynamic data, Map? headers, Map? env, + bool removeCookies = false, + String? apiTarget, @Deprecated('Will be removed in v8. Use [data] instead') Map? other, - bool removeCookies = false, }) => SentryRequest( url: url ?? this.url, @@ -160,8 +173,9 @@ class SentryRequest { data: data ?? _data, headers: headers ?? _headers, env: env ?? _env, + fragment: fragment ?? this.fragment, + apiTarget: apiTarget ?? this.apiTarget, // ignore: deprecated_member_use_from_same_package other: other ?? _other, - fragment: fragment, ); } diff --git a/dart/lib/src/protocol/sentry_response.dart b/dart/lib/src/protocol/sentry_response.dart index f4438a3b0e..91faaa37eb 100644 --- a/dart/lib/src/protocol/sentry_response.dart +++ b/dart/lib/src/protocol/sentry_response.dart @@ -26,12 +26,31 @@ class SentryResponse { /// Cookie key-value pairs as string. final String? cookies; - SentryResponse( - {this.bodySize, - this.statusCode, - Map? headers, - String? cookies}) - : _headers = headers != null ? Map.from(headers) : null, + final Object? _data; + + /// Response data in any format that makes sense. + /// + /// SDKs should discard large and binary bodies by default. + /// Can be given as a string or structural data of any format. + Object? get data { + final typedData = _data; + if (typedData is List) { + return List.unmodifiable(typedData); + } else if (typedData is Map) { + return Map.unmodifiable(typedData); + } + + return _data; + } + + SentryResponse({ + this.bodySize, + this.statusCode, + Map? headers, + String? cookies, + Object? data, + }) : _data = data, + _headers = headers != null ? Map.from(headers) : null, // Look for a 'Set-Cookie' header (case insensitive) if not given. cookies = cookies ?? headers?.entries @@ -45,6 +64,7 @@ class SentryResponse { cookies: json['cookies'], bodySize: json['body_size'], statusCode: json['status_code'], + data: json['data'], ); } @@ -55,6 +75,7 @@ class SentryResponse { if (cookies != null) 'cookies': cookies, if (bodySize != null) 'body_size': bodySize, if (statusCode != null) 'status_code': statusCode, + if (data != null) 'data': data, }; } @@ -63,12 +84,14 @@ class SentryResponse { int? bodySize, Map? headers, String? cookies, + Object? data, }) => SentryResponse( headers: headers ?? _headers, cookies: cookies ?? this.cookies, bodySize: bodySize ?? this.bodySize, statusCode: statusCode ?? this.statusCode, + data: data ?? this.data, ); SentryResponse clone() => SentryResponse( @@ -76,5 +99,6 @@ class SentryResponse { headers: headers, cookies: cookies, statusCode: statusCode, + data: data, ); } diff --git a/dart/test/protocol/sentry_request_test.dart b/dart/test/protocol/sentry_request_test.dart index 6e8342b51d..a1d186632b 100644 --- a/dart/test/protocol/sentry_request_test.dart +++ b/dart/test/protocol/sentry_request_test.dart @@ -11,6 +11,7 @@ void main() { data: {'key': 'value'}, headers: {'header_key': 'header_value'}, env: {'env_key': 'env_value'}, + apiTarget: 'GraphQL', // ignore: deprecated_member_use_from_same_package other: {'other_key': 'other_value'}, ); @@ -23,6 +24,7 @@ void main() { 'data': {'key': 'value'}, 'headers': {'header_key': 'header_value'}, 'env': {'env_key': 'env_value'}, + 'api_target': 'GraphQL', 'other': {'other_key': 'other_value'}, }; diff --git a/dart/test/protocol/sentry_response_test.dart b/dart/test/protocol/sentry_response_test.dart index 9d983d6b67..6ae3b0e361 100644 --- a/dart/test/protocol/sentry_response_test.dart +++ b/dart/test/protocol/sentry_response_test.dart @@ -8,6 +8,7 @@ void main() { statusCode: 200, headers: {'header_key': 'header_value'}, cookies: 'foo=bar, another=cookie', + data: 'foo', ); final sentryResponseJson = { @@ -15,6 +16,7 @@ void main() { 'status_code': 200, 'headers': {'header_key': 'header_value'}, 'cookies': 'foo=bar, another=cookie', + 'data': 'foo', }; group('json', () {