@@ -27,16 +27,37 @@ import 'http_logging.dart';
2727/// debugging information which is included in logs, but not sent to the
2828/// requester.
2929class BadRequestException implements Exception {
30+ /// The HTTP status code for the response.
31+ ///
32+ /// Must be between 400 and 499.
3033 final int statusCode;
34+
35+ /// The message sent to the requester.
3136 final String message;
37+
38+ /// The error that caused this exception.
3239 final Object ? innerError;
40+
41+ /// The stack trace of the error that caused this exception.
3342 final StackTrace ? innerStack;
3443
44+ /// An explicit error status string (e.g., `INVALID_ARGUMENT` ).
45+ ///
46+ /// See https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
47+ final String ? status;
48+
49+ /// Structured error details.
50+ ///
51+ /// See https://google.aip.dev/193#statusdetails
52+ final List <Map <String , Object ?>>? details;
53+
3554 BadRequestException (
3655 this .statusCode,
3756 this .message, {
3857 this .innerError,
3958 this .innerStack,
59+ this .status,
60+ this .details,
4061 }) : assert (message.isNotEmpty) {
4162 if (statusCode < 400 || statusCode > 499 ) {
4263 throw ArgumentError .value (
@@ -47,6 +68,143 @@ class BadRequestException implements Exception {
4768 }
4869 }
4970
71+ /// Creates a new [BadRequestException] with status code 400.
72+ factory BadRequestException .badRequest (
73+ String message, {
74+ Object ? innerError,
75+ StackTrace ? innerStack,
76+ String ? status,
77+ List <Map <String , Object ?>>? details,
78+ }) => BadRequestException (
79+ 400 ,
80+ message,
81+ innerError: innerError,
82+ innerStack: innerStack,
83+ status: status,
84+ details: details,
85+ );
86+
87+ /// Creates a new [BadRequestException] with status code 401.
88+ ///
89+ /// The request does not have valid authentication credentials for the
90+ /// operation.
91+ factory BadRequestException .unauthorized (
92+ String message, {
93+ Object ? innerError,
94+ StackTrace ? innerStack,
95+ String ? status = 'UNAUTHENTICATED' ,
96+ List <Map <String , Object ?>>? details,
97+ }) => BadRequestException (
98+ 401 ,
99+ message,
100+ innerError: innerError,
101+ innerStack: innerStack,
102+ status: status,
103+ details: details,
104+ );
105+
106+ /// Creates a new [BadRequestException] with status code 403.
107+ ///
108+ /// The caller does not have permission to execute the specified
109+ /// operation. `PERMISSION_DENIED` must not be used for rejections
110+ /// caused by exhausting some resource (use `RESOURCE_EXHAUSTED`
111+ /// instead for those errors). `PERMISSION_DENIED` must not be
112+ /// used if the caller can not be identified (use `UNAUTHENTICATED`
113+ /// instead for those errors). This error code does not imply the
114+ /// request is valid or the requested entity exists or satisfies
115+ /// other pre-conditions.
116+ factory BadRequestException .forbidden (
117+ String message, {
118+ Object ? innerError,
119+ StackTrace ? innerStack,
120+ String ? status = 'PERMISSION_DENIED' ,
121+ List <Map <String , Object ?>>? details,
122+ }) => BadRequestException (
123+ 403 ,
124+ message,
125+ innerError: innerError,
126+ innerStack: innerStack,
127+ status: status,
128+ details: details,
129+ );
130+
131+ /// Creates a new [BadRequestException] with status code 404.
132+ ///
133+ /// Some requested entity (e.g., file or directory) was not found.
134+ ///
135+ /// Note to server developers: if a request is denied for an entire class
136+ /// of users, such as gradual feature rollout or undocumented allowlist,
137+ /// `NOT_FOUND` may be used. If a request is denied for some users within
138+ /// a class of users, such as user-based access control, `PERMISSION_DENIED`
139+ /// must be used.
140+ factory BadRequestException .notFound (
141+ String message, {
142+ Object ? innerError,
143+ StackTrace ? innerStack,
144+ String ? status = 'NOT_FOUND' ,
145+ List <Map <String , Object ?>>? details,
146+ }) => BadRequestException (
147+ 404 ,
148+ message,
149+ innerError: innerError,
150+ innerStack: innerStack,
151+ status: status,
152+ details: details,
153+ );
154+
155+ /// Creates a new [BadRequestException] with status code 409.
156+ factory BadRequestException .conflict (
157+ String message, {
158+ Object ? innerError,
159+ StackTrace ? innerStack,
160+ String ? status,
161+ List <Map <String , Object ?>>? details,
162+ }) => BadRequestException (
163+ 409 ,
164+ message,
165+ innerError: innerError,
166+ innerStack: innerStack,
167+ status: status,
168+ details: details,
169+ );
170+
171+ /// Creates a new [BadRequestException] with status code 429.
172+ ///
173+ /// Some resource has been exhausted, perhaps a per-user quota, or
174+ /// perhaps the entire file system is out of space.
175+ factory BadRequestException .tooManyRequests (
176+ String message, {
177+ Object ? innerError,
178+ StackTrace ? innerStack,
179+ String ? status = 'RESOURCE_EXHAUSTED' ,
180+ List <Map <String , Object ?>>? details,
181+ }) => BadRequestException (
182+ 429 ,
183+ message,
184+ innerError: innerError,
185+ innerStack: innerStack,
186+ status: status,
187+ details: details,
188+ );
189+
50190 @override
51- String toString () => '$message ($statusCode )' ;
191+ String toString () {
192+ final buffer = StringBuffer ('$message ($statusCode )' );
193+ if (status != null && status! .isNotEmpty) buffer.write (' [$status ]' );
194+ if (details != null && details! .isNotEmpty) {
195+ buffer.write (' Details: $details ' );
196+ }
197+ return buffer.toString ();
198+ }
199+
200+ /// Returns a JSON representation of the error, suitable for including in a
201+ /// response body.
202+ Map <String , Object ?> toJson () => {
203+ 'error' : {
204+ 'code' : statusCode,
205+ 'message' : message,
206+ if (status != null && status! .isNotEmpty) 'status' : status,
207+ if (details != null && details! .isNotEmpty) 'details' : details,
208+ },
209+ };
52210}
0 commit comments