4
4
// ignore_for_file: invalid_annotation_target, unused_import
5
5
6
6
import 'dart:convert' ;
7
- import 'dart:io' as io;
8
7
import 'dart:typed_data' ;
9
8
10
9
import 'package:http/http.dart' as http;
@@ -21,7 +20,7 @@ enum HttpMethod { get, put, post, delete, options, head, patch, trace }
21
20
// ==========================================
22
21
23
22
/// HTTP exception handler for ChromaApiClient
24
- class ChromaApiClientException implements io. HttpException {
23
+ class ChromaApiClientException implements Exception {
25
24
ChromaApiClientException ({
26
25
required this .message,
27
26
required this .uri,
@@ -30,9 +29,7 @@ class ChromaApiClientException implements io.HttpException {
30
29
this .body,
31
30
});
32
31
33
- @override
34
32
final String message;
35
- @override
36
33
final Uri uri;
37
34
final HttpMethod method;
38
35
final int ? code;
@@ -69,10 +66,12 @@ class ChromaApiClient {
69
66
///
70
67
/// - [ChromaApiClient.baseUrl] Override base URL (default: server url defined in spec)
71
68
/// - [ChromaApiClient.headers] Global headers to be sent with every request
69
+ /// - [ChromaApiClient.queryParams] Global query parameters to be sent with every request
72
70
/// - [ChromaApiClient.client] Override HTTP client to use for requests
73
71
ChromaApiClient ({
74
72
this .baseUrl,
75
73
this .headers = const {},
74
+ this .queryParams = const {},
76
75
http.Client ? client,
77
76
}) : assert (
78
77
baseUrl == null || baseUrl.startsWith ('http' ),
@@ -90,6 +89,9 @@ class ChromaApiClient {
90
89
/// Global headers to be sent with every request
91
90
final Map <String , String > headers;
92
91
92
+ /// Global query parameters to be sent with every request
93
+ final Map <String , dynamic > queryParams;
94
+
93
95
/// HTTP client for requests
94
96
final http.Client client;
95
97
@@ -132,12 +134,20 @@ class ChromaApiClient {
132
134
}
133
135
134
136
// ------------------------------------------
135
- // METHOD: makeRequestStream
137
+ // METHOD: _jsonDecode
136
138
// ------------------------------------------
137
139
138
- /// Reusable request stream method
140
+ dynamic _jsonDecode (http.Response r) {
141
+ return json.decode (utf8.decode (r.bodyBytes));
142
+ }
143
+
144
+ // ------------------------------------------
145
+ // METHOD: _request
146
+ // ------------------------------------------
147
+
148
+ /// Reusable request method
139
149
@protected
140
- Future <http.StreamedResponse > makeRequestStream ({
150
+ Future <http.StreamedResponse > _request ({
141
151
required String baseUrl,
142
152
required String path,
143
153
required HttpMethod method,
@@ -157,6 +167,9 @@ class ChromaApiClient {
157
167
'baseUrl is required, but none defined in spec or provided by user' ,
158
168
);
159
169
170
+ // Add global query parameters
171
+ queryParams = {...queryParams, ...this .queryParams};
172
+
160
173
// Ensure query parameters are strings or iterable of strings
161
174
queryParams = queryParams.map ((key, value) {
162
175
if (value is Iterable ) {
@@ -189,46 +202,75 @@ class ChromaApiClient {
189
202
headers.addAll (this .headers);
190
203
191
204
// Build the request object
192
- late http.StreamedResponse response;
193
- try {
194
- http.BaseRequest request;
195
- if (isMultipart) {
196
- // Handle multipart request
197
- request = http.MultipartRequest (method.name, uri);
198
- request = request as http.MultipartRequest ;
199
- if (body is List <http.MultipartFile >) {
200
- request.files.addAll (body);
201
- } else {
202
- request.files.add (body as http.MultipartFile );
203
- }
205
+ http.BaseRequest request;
206
+ if (isMultipart) {
207
+ // Handle multipart request
208
+ request = http.MultipartRequest (method.name, uri);
209
+ request = request as http.MultipartRequest ;
210
+ if (body is List <http.MultipartFile >) {
211
+ request.files.addAll (body);
204
212
} else {
205
- // Handle normal request
206
- request = http.Request (method.name, uri);
207
- request = request as http.Request ;
208
- try {
209
- if (body != null ) {
210
- request.body = json.encode (body);
211
- }
212
- } catch (e) {
213
- // Handle request encoding error
214
- throw ChromaApiClientException (
215
- uri: uri,
216
- method: method,
217
- message: 'Could not encode: ${body .runtimeType }' ,
218
- body: e,
219
- );
213
+ request.files.add (body as http.MultipartFile );
214
+ }
215
+ } else {
216
+ // Handle normal request
217
+ request = http.Request (method.name, uri);
218
+ request = request as http.Request ;
219
+ try {
220
+ if (body != null ) {
221
+ request.body = json.encode (body);
220
222
}
223
+ } catch (e) {
224
+ // Handle request encoding error
225
+ throw ChromaApiClientException (
226
+ uri: uri,
227
+ method: method,
228
+ message: 'Could not encode: ${body .runtimeType }' ,
229
+ body: e,
230
+ );
221
231
}
232
+ }
222
233
223
- // Add request headers
224
- request.headers.addAll (headers);
234
+ // Add request headers
235
+ request.headers.addAll (headers);
225
236
226
- // Handle user request middleware
227
- request = await onRequest (request);
237
+ // Handle user request middleware
238
+ request = await onRequest (request);
239
+
240
+ // Submit request
241
+ return await client.send (request);
242
+ }
228
243
229
- // Submit request
230
- response = await client.send (request);
244
+ // ------------------------------------------
245
+ // METHOD: makeRequestStream
246
+ // ------------------------------------------
231
247
248
+ /// Reusable request stream method
249
+ @protected
250
+ Future <http.StreamedResponse > makeRequestStream ({
251
+ required String baseUrl,
252
+ required String path,
253
+ required HttpMethod method,
254
+ Map <String , dynamic > queryParams = const {},
255
+ Map <String , String > headerParams = const {},
256
+ bool isMultipart = false ,
257
+ String requestType = '' ,
258
+ String responseType = '' ,
259
+ Object ? body,
260
+ }) async {
261
+ final uri = Uri .parse ((this .baseUrl ?? baseUrl) + path);
262
+ late http.StreamedResponse response;
263
+ try {
264
+ response = await _request (
265
+ baseUrl: baseUrl,
266
+ path: path,
267
+ method: method,
268
+ queryParams: queryParams,
269
+ headerParams: headerParams,
270
+ requestType: requestType,
271
+ responseType: responseType,
272
+ body: body,
273
+ );
232
274
// Handle user response middleware
233
275
response = await onStreamedResponse (response);
234
276
} catch (e) {
@@ -273,8 +315,10 @@ class ChromaApiClient {
273
315
String responseType = '' ,
274
316
Object ? body,
275
317
}) async {
318
+ final uri = Uri .parse ((this .baseUrl ?? baseUrl) + path);
319
+ late http.Response response;
276
320
try {
277
- final streamedResponse = await makeRequestStream (
321
+ final streamedResponse = await _request (
278
322
baseUrl: baseUrl,
279
323
path: path,
280
324
method: method,
@@ -284,21 +328,32 @@ class ChromaApiClient {
284
328
responseType: responseType,
285
329
body: body,
286
330
);
287
- final response = await http.Response .fromStream (streamedResponse);
288
-
331
+ response = await http.Response .fromStream (streamedResponse);
289
332
// Handle user response middleware
290
- return await onResponse (response);
291
- } on ChromaApiClientException {
292
- rethrow ;
333
+ response = await onResponse (response);
293
334
} catch (e) {
294
335
// Handle request and response errors
295
336
throw ChromaApiClientException (
296
- uri: Uri . parse (( this .baseUrl ?? baseUrl) + path) ,
337
+ uri: uri ,
297
338
method: method,
298
339
message: 'Response error' ,
299
340
body: e,
300
341
);
301
342
}
343
+
344
+ // Check for successful response
345
+ if ((response.statusCode ~ / 100 ) == 2 ) {
346
+ return response;
347
+ }
348
+
349
+ // Handle unsuccessful response
350
+ throw ChromaApiClientException (
351
+ uri: uri,
352
+ method: method,
353
+ message: 'Unsuccessful response' ,
354
+ code: response.statusCode,
355
+ body: response.body,
356
+ );
302
357
}
303
358
304
359
// ------------------------------------------
@@ -317,7 +372,7 @@ class ChromaApiClient {
317
372
requestType: '' ,
318
373
responseType: 'application/json' ,
319
374
);
320
- return Map <String , int >.from (json. decode (r.body ));
375
+ return Map <String , int >.from (_jsonDecode (r ));
321
376
}
322
377
323
378
// ------------------------------------------
@@ -336,7 +391,7 @@ class ChromaApiClient {
336
391
requestType: '' ,
337
392
responseType: 'application/json' ,
338
393
);
339
- return json. decode (r.body );
394
+ return _jsonDecode (r );
340
395
}
341
396
342
397
// ------------------------------------------
@@ -374,7 +429,7 @@ class ChromaApiClient {
374
429
requestType: '' ,
375
430
responseType: 'application/json' ,
376
431
);
377
- return Map <String , int >.from (json. decode (r.body ));
432
+ return Map <String , int >.from (_jsonDecode (r ));
378
433
}
379
434
380
435
// ------------------------------------------
@@ -423,7 +478,7 @@ class ChromaApiClient {
423
478
'tenant' : tenant,
424
479
},
425
480
);
426
- final list = json. decode (r.body ) as List ;
481
+ final list = _jsonDecode (r ) as List ;
427
482
return list.map ((e) => DatabaseType .fromJson (e)).toList ();
428
483
}
429
484
@@ -453,7 +508,7 @@ class ChromaApiClient {
453
508
'tenant' : tenant,
454
509
},
455
510
);
456
- return DatabaseType .fromJson (json. decode (r.body ));
511
+ return DatabaseType .fromJson (_jsonDecode (r ));
457
512
}
458
513
459
514
// ------------------------------------------
@@ -477,7 +532,7 @@ class ChromaApiClient {
477
532
responseType: 'application/json' ,
478
533
body: request,
479
534
);
480
- final list = json. decode (r.body ) as List ;
535
+ final list = _jsonDecode (r ) as List ;
481
536
return list.map ((e) => TenantType .fromJson (e)).toList ();
482
537
}
483
538
@@ -501,7 +556,7 @@ class ChromaApiClient {
501
556
requestType: '' ,
502
557
responseType: 'application/json' ,
503
558
);
504
- return TenantType .fromJson (json. decode (r.body ));
559
+ return TenantType .fromJson (_jsonDecode (r ));
505
560
}
506
561
507
562
// ------------------------------------------
@@ -531,7 +586,7 @@ class ChromaApiClient {
531
586
'database' : database,
532
587
},
533
588
);
534
- final list = json. decode (r.body ) as List ;
589
+ final list = _jsonDecode (r ) as List ;
535
590
return list.map ((e) => CollectionType .fromJson (e)).toList ();
536
591
}
537
592
@@ -566,7 +621,7 @@ class ChromaApiClient {
566
621
'database' : database,
567
622
},
568
623
);
569
- return CollectionType .fromJson (json. decode (r.body ));
624
+ return CollectionType .fromJson (_jsonDecode (r ));
570
625
}
571
626
572
627
// ------------------------------------------
@@ -674,7 +729,7 @@ class ChromaApiClient {
674
729
responseType: 'application/json' ,
675
730
body: request,
676
731
);
677
- return GetResponse .fromJson (json. decode (r.body ));
732
+ return GetResponse .fromJson (_jsonDecode (r ));
678
733
}
679
734
680
735
// ------------------------------------------
@@ -701,7 +756,7 @@ class ChromaApiClient {
701
756
responseType: 'application/json' ,
702
757
body: request,
703
758
);
704
- return List <String >.from (json. decode (r.body ));
759
+ return List <String >.from (_jsonDecode (r ));
705
760
}
706
761
707
762
// ------------------------------------------
@@ -724,7 +779,7 @@ class ChromaApiClient {
724
779
requestType: '' ,
725
780
responseType: 'application/json' ,
726
781
);
727
- return json. decode (r.body );
782
+ return _jsonDecode (r );
728
783
}
729
784
730
785
// ------------------------------------------
@@ -751,7 +806,7 @@ class ChromaApiClient {
751
806
responseType: 'application/json' ,
752
807
body: request,
753
808
);
754
- return QueryResponse .fromJson (json. decode (r.body ));
809
+ return QueryResponse .fromJson (_jsonDecode (r ));
755
810
}
756
811
757
812
// ------------------------------------------
@@ -784,7 +839,7 @@ class ChromaApiClient {
784
839
'database' : database,
785
840
},
786
841
);
787
- return CollectionType .fromJson (json. decode (r.body ));
842
+ return CollectionType .fromJson (_jsonDecode (r ));
788
843
}
789
844
790
845
// ------------------------------------------
0 commit comments