Skip to content

Commit f66fb62

Browse files
committed
feat(exception): enhance FirebaseAppException with JSON serialization and update error codes
1 parent d2956ce commit f66fb62

File tree

5 files changed

+309
-28
lines changed

5 files changed

+309
-28
lines changed

packages/dart_firebase_admin/lib/src/app/app_exception.dart

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,13 @@
11
part of '../app.dart';
22

33
/// Exception thrown for Firebase app initialization and lifecycle errors.
4-
class FirebaseAppException implements Exception {
4+
class FirebaseAppException extends FirebaseAdminException {
55
FirebaseAppException(this.errorCode, [String? message])
6-
: code = errorCode.code,
7-
_message = message;
6+
: super('app', errorCode.code, message ?? errorCode.message);
87

98
/// The error code object containing code and default message.
109
final AppErrorCode errorCode;
1110

12-
/// The error code string.
13-
final String code;
14-
15-
/// Custom error message, if provided.
16-
final String? _message;
17-
18-
/// The error message. Returns custom message if provided, otherwise default.
19-
String get message => _message ?? errorCode.message;
20-
2111
@override
2212
String toString() => 'FirebaseAppException($code): $message';
2313
}

packages/dart_firebase_admin/lib/src/app/exception.dart

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ class FirebaseArrayIndexError {
1111

1212
/// The error object.
1313
final FirebaseAdminException error;
14+
15+
/// Converts this error to a JSON-serializable map.
16+
///
17+
/// This is useful for structured logging and error reporting.
18+
/// The returned map contains:
19+
/// - `index`: The index of the errored item
20+
/// - `error`: The serialized error object (with code and message)
21+
Map<String, dynamic> toJson() {
22+
return {'index': index, 'error': error.toJson()};
23+
}
1424
}
1525

1626
/// A set of platform level error codes.
@@ -78,6 +88,27 @@ abstract class FirebaseAdminException implements Exception {
7888
/// this message should not be displayed in your application.
7989
String get message => _message ?? _platformErrorCodeMessage(_code);
8090

91+
/// Converts this exception to a JSON-serializable map.
92+
///
93+
/// This is useful for structured logging and error reporting in GCP Cloud Logging.
94+
/// The returned map contains:
95+
/// - `code`: The error code string (e.g., "auth/invalid-uid")
96+
/// - `message`: The error message
97+
///
98+
/// Example:
99+
/// ```dart
100+
/// try {
101+
/// // ...
102+
/// } catch (e) {
103+
/// if (e is FirebaseAdminException) {
104+
/// print(jsonEncode(e.toJson())); // Logs structured JSON
105+
/// }
106+
/// }
107+
/// ```
108+
Map<String, dynamic> toJson() {
109+
return {'code': code, 'message': message};
110+
}
111+
81112
@override
82113
String toString() {
83114
return '$runtimeType($code, $message)';

packages/dart_firebase_admin/test/app/app_registry_test.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ void main() {
165165
() => registry.fetchOptionsFromEnvironment(),
166166
throwsA(
167167
isA<FirebaseAppException>()
168-
.having((e) => e.code, 'code', 'invalid-argument')
168+
.having((e) => e.code, 'code', 'app/invalid-argument')
169169
.having(
170170
(e) => e.message,
171171
'message',
@@ -188,7 +188,7 @@ void main() {
188188
() => registry.fetchOptionsFromEnvironment(),
189189
throwsA(
190190
isA<FirebaseAppException>()
191-
.having((e) => e.code, 'code', 'invalid-argument')
191+
.having((e) => e.code, 'code', 'app/invalid-argument')
192192
.having(
193193
(e) => e.message,
194194
'message',
@@ -238,7 +238,7 @@ void main() {
238238
isA<FirebaseAppException>().having(
239239
(e) => e.code,
240240
'code',
241-
'invalid-app-options',
241+
'app/invalid-app-options',
242242
),
243243
),
244244
);
@@ -263,7 +263,7 @@ void main() {
263263
isA<FirebaseAppException>().having(
264264
(e) => e.code,
265265
'code',
266-
'invalid-app-options',
266+
'app/invalid-app-options',
267267
),
268268
),
269269
);
@@ -306,7 +306,7 @@ void main() {
306306
isA<FirebaseAppException>().having(
307307
(e) => e.code,
308308
'code',
309-
'duplicate-app',
309+
'app/duplicate-app',
310310
),
311311
),
312312
);
@@ -365,7 +365,7 @@ void main() {
365365
),
366366
throwsA(
367367
isA<FirebaseAppException>()
368-
.having((e) => e.code, 'code', 'invalid-app-name')
368+
.having((e) => e.code, 'code', 'app/invalid-app-name')
369369
.having(
370370
(e) => e.message,
371371
'message',
@@ -380,7 +380,7 @@ void main() {
380380
() => registry.getApp(''),
381381
throwsA(
382382
isA<FirebaseAppException>()
383-
.having((e) => e.code, 'code', 'invalid-app-name')
383+
.having((e) => e.code, 'code', 'app/invalid-app-name')
384384
.having(
385385
(e) => e.message,
386386
'message',
@@ -417,7 +417,7 @@ void main() {
417417
() => registry.getApp(),
418418
throwsA(
419419
isA<FirebaseAppException>()
420-
.having((e) => e.code, 'code', 'no-app')
420+
.having((e) => e.code, 'code', 'app/no-app')
421421
.having(
422422
(e) => e.message,
423423
'message',
@@ -435,7 +435,7 @@ void main() {
435435
() => registry.getApp('my-app'),
436436
throwsA(
437437
isA<FirebaseAppException>()
438-
.having((e) => e.code, 'code', 'no-app')
438+
.having((e) => e.code, 'code', 'app/no-app')
439439
.having(
440440
(e) => e.message,
441441
'message',

0 commit comments

Comments
 (0)