Skip to content

Commit 498a103

Browse files
davidmiglozKennethKnudsen97
authored andcommitted
fix(chromadb): Decode JSON responses as UTF-8 (davidmigloz#234) (davidmigloz#235)
Related to davidmigloz#233 (ref tazatechnology/openapi_spec#43)
1 parent 4ed87be commit 498a103

20 files changed

+140
-81
lines changed

packages/chromadb/lib/src/chroma_client.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ class ChromaClient {
1616
this.database = 'default_database',
1717
final String baseUrl = 'http://localhost:8000',
1818
final Map<String, String>? headers,
19+
final Map<String, dynamic>? queryParams,
1920
final http.Client? client,
2021
}) : _api = ChromaApiClient(
2122
baseUrl: baseUrl,
2223
headers: headers ?? const {},
24+
queryParams: queryParams ?? const {},
2325
client: client,
2426
);
2527

packages/chromadb/lib/src/generated/client.dart

Lines changed: 116 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// ignore_for_file: invalid_annotation_target, unused_import
55

66
import 'dart:convert';
7-
import 'dart:io' as io;
87
import 'dart:typed_data';
98

109
import 'package:http/http.dart' as http;
@@ -21,7 +20,7 @@ enum HttpMethod { get, put, post, delete, options, head, patch, trace }
2120
// ==========================================
2221

2322
/// HTTP exception handler for ChromaApiClient
24-
class ChromaApiClientException implements io.HttpException {
23+
class ChromaApiClientException implements Exception {
2524
ChromaApiClientException({
2625
required this.message,
2726
required this.uri,
@@ -30,9 +29,7 @@ class ChromaApiClientException implements io.HttpException {
3029
this.body,
3130
});
3231

33-
@override
3432
final String message;
35-
@override
3633
final Uri uri;
3734
final HttpMethod method;
3835
final int? code;
@@ -69,10 +66,12 @@ class ChromaApiClient {
6966
///
7067
/// - [ChromaApiClient.baseUrl] Override base URL (default: server url defined in spec)
7168
/// - [ChromaApiClient.headers] Global headers to be sent with every request
69+
/// - [ChromaApiClient.queryParams] Global query parameters to be sent with every request
7270
/// - [ChromaApiClient.client] Override HTTP client to use for requests
7371
ChromaApiClient({
7472
this.baseUrl,
7573
this.headers = const {},
74+
this.queryParams = const {},
7675
http.Client? client,
7776
}) : assert(
7877
baseUrl == null || baseUrl.startsWith('http'),
@@ -90,6 +89,9 @@ class ChromaApiClient {
9089
/// Global headers to be sent with every request
9190
final Map<String, String> headers;
9291

92+
/// Global query parameters to be sent with every request
93+
final Map<String, dynamic> queryParams;
94+
9395
/// HTTP client for requests
9496
final http.Client client;
9597

@@ -132,12 +134,20 @@ class ChromaApiClient {
132134
}
133135

134136
// ------------------------------------------
135-
// METHOD: makeRequestStream
137+
// METHOD: _jsonDecode
136138
// ------------------------------------------
137139

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
139149
@protected
140-
Future<http.StreamedResponse> makeRequestStream({
150+
Future<http.StreamedResponse> _request({
141151
required String baseUrl,
142152
required String path,
143153
required HttpMethod method,
@@ -157,6 +167,9 @@ class ChromaApiClient {
157167
'baseUrl is required, but none defined in spec or provided by user',
158168
);
159169

170+
// Add global query parameters
171+
queryParams = {...queryParams, ...this.queryParams};
172+
160173
// Ensure query parameters are strings or iterable of strings
161174
queryParams = queryParams.map((key, value) {
162175
if (value is Iterable) {
@@ -189,46 +202,75 @@ class ChromaApiClient {
189202
headers.addAll(this.headers);
190203

191204
// 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);
204212
} 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);
220222
}
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+
);
221231
}
232+
}
222233

223-
// Add request headers
224-
request.headers.addAll(headers);
234+
// Add request headers
235+
request.headers.addAll(headers);
225236

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+
}
228243

229-
// Submit request
230-
response = await client.send(request);
244+
// ------------------------------------------
245+
// METHOD: makeRequestStream
246+
// ------------------------------------------
231247

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+
);
232274
// Handle user response middleware
233275
response = await onStreamedResponse(response);
234276
} catch (e) {
@@ -273,8 +315,10 @@ class ChromaApiClient {
273315
String responseType = '',
274316
Object? body,
275317
}) async {
318+
final uri = Uri.parse((this.baseUrl ?? baseUrl) + path);
319+
late http.Response response;
276320
try {
277-
final streamedResponse = await makeRequestStream(
321+
final streamedResponse = await _request(
278322
baseUrl: baseUrl,
279323
path: path,
280324
method: method,
@@ -284,21 +328,32 @@ class ChromaApiClient {
284328
responseType: responseType,
285329
body: body,
286330
);
287-
final response = await http.Response.fromStream(streamedResponse);
288-
331+
response = await http.Response.fromStream(streamedResponse);
289332
// Handle user response middleware
290-
return await onResponse(response);
291-
} on ChromaApiClientException {
292-
rethrow;
333+
response = await onResponse(response);
293334
} catch (e) {
294335
// Handle request and response errors
295336
throw ChromaApiClientException(
296-
uri: Uri.parse((this.baseUrl ?? baseUrl) + path),
337+
uri: uri,
297338
method: method,
298339
message: 'Response error',
299340
body: e,
300341
);
301342
}
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+
);
302357
}
303358

304359
// ------------------------------------------
@@ -317,7 +372,7 @@ class ChromaApiClient {
317372
requestType: '',
318373
responseType: 'application/json',
319374
);
320-
return Map<String, int>.from(json.decode(r.body));
375+
return Map<String, int>.from(_jsonDecode(r));
321376
}
322377

323378
// ------------------------------------------
@@ -336,7 +391,7 @@ class ChromaApiClient {
336391
requestType: '',
337392
responseType: 'application/json',
338393
);
339-
return json.decode(r.body);
394+
return _jsonDecode(r);
340395
}
341396

342397
// ------------------------------------------
@@ -374,7 +429,7 @@ class ChromaApiClient {
374429
requestType: '',
375430
responseType: 'application/json',
376431
);
377-
return Map<String, int>.from(json.decode(r.body));
432+
return Map<String, int>.from(_jsonDecode(r));
378433
}
379434

380435
// ------------------------------------------
@@ -423,7 +478,7 @@ class ChromaApiClient {
423478
'tenant': tenant,
424479
},
425480
);
426-
final list = json.decode(r.body) as List;
481+
final list = _jsonDecode(r) as List;
427482
return list.map((e) => DatabaseType.fromJson(e)).toList();
428483
}
429484

@@ -453,7 +508,7 @@ class ChromaApiClient {
453508
'tenant': tenant,
454509
},
455510
);
456-
return DatabaseType.fromJson(json.decode(r.body));
511+
return DatabaseType.fromJson(_jsonDecode(r));
457512
}
458513

459514
// ------------------------------------------
@@ -477,7 +532,7 @@ class ChromaApiClient {
477532
responseType: 'application/json',
478533
body: request,
479534
);
480-
final list = json.decode(r.body) as List;
535+
final list = _jsonDecode(r) as List;
481536
return list.map((e) => TenantType.fromJson(e)).toList();
482537
}
483538

@@ -501,7 +556,7 @@ class ChromaApiClient {
501556
requestType: '',
502557
responseType: 'application/json',
503558
);
504-
return TenantType.fromJson(json.decode(r.body));
559+
return TenantType.fromJson(_jsonDecode(r));
505560
}
506561

507562
// ------------------------------------------
@@ -531,7 +586,7 @@ class ChromaApiClient {
531586
'database': database,
532587
},
533588
);
534-
final list = json.decode(r.body) as List;
589+
final list = _jsonDecode(r) as List;
535590
return list.map((e) => CollectionType.fromJson(e)).toList();
536591
}
537592

@@ -566,7 +621,7 @@ class ChromaApiClient {
566621
'database': database,
567622
},
568623
);
569-
return CollectionType.fromJson(json.decode(r.body));
624+
return CollectionType.fromJson(_jsonDecode(r));
570625
}
571626

572627
// ------------------------------------------
@@ -674,7 +729,7 @@ class ChromaApiClient {
674729
responseType: 'application/json',
675730
body: request,
676731
);
677-
return GetResponse.fromJson(json.decode(r.body));
732+
return GetResponse.fromJson(_jsonDecode(r));
678733
}
679734

680735
// ------------------------------------------
@@ -701,7 +756,7 @@ class ChromaApiClient {
701756
responseType: 'application/json',
702757
body: request,
703758
);
704-
return List<String>.from(json.decode(r.body));
759+
return List<String>.from(_jsonDecode(r));
705760
}
706761

707762
// ------------------------------------------
@@ -724,7 +779,7 @@ class ChromaApiClient {
724779
requestType: '',
725780
responseType: 'application/json',
726781
);
727-
return json.decode(r.body);
782+
return _jsonDecode(r);
728783
}
729784

730785
// ------------------------------------------
@@ -751,7 +806,7 @@ class ChromaApiClient {
751806
responseType: 'application/json',
752807
body: request,
753808
);
754-
return QueryResponse.fromJson(json.decode(r.body));
809+
return QueryResponse.fromJson(_jsonDecode(r));
755810
}
756811

757812
// ------------------------------------------
@@ -784,7 +839,7 @@ class ChromaApiClient {
784839
'database': database,
785840
},
786841
);
787-
return CollectionType.fromJson(json.decode(r.body));
842+
return CollectionType.fromJson(_jsonDecode(r));
788843
}
789844

790845
// ------------------------------------------

packages/chromadb/lib/src/generated/schema/add_embedding.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// coverage:ignore-file
22
// GENERATED CODE - DO NOT MODIFY BY HAND
33
// ignore_for_file: type=lint
4-
// ignore_for_file: invalid_annotation_target, unused_import
4+
// ignore_for_file: invalid_annotation_target
55
part of chroma_api_schema;
66

77
// ==========================================

0 commit comments

Comments
 (0)