diff --git a/README.md b/README.md
index f2e62ba6d29db3b617f4d956a706dc82fabf3349..ecfa3ea1b289475209f93097313b6f84b95aea82 100644
--- a/README.md
+++ b/README.md
@@ -7,18 +7,18 @@ This is the _unofficial_ MinIO Dart Client SDK that provides simple APIs to acce
 
 ## API
 
-| Bucket operations       | Object operations        | Presigned operations | Bucket Policy & Notification operations |
-|-------------------------|--------------------------|----------------------|-----------------------------------------|
-| [makeBucket]            | [getObject]              | [presignedUrl]       | [getBucketNotification]                 |
-| [listBuckets]           | [getPartialObject]       | [presignedGetObject] | [setBucketNotification]                 |
-| [bucketExists]          | [fGetObject]             | [presignedPutObject] | [removeAllBucketNotification]           |
-| [removeBucket]          | [putObject]              | [presignedPostPolicy]| [listenBucketNotification]              |
-| [listObjects]           | [fPutObject]             |                      | [getBucketPolicy]                       |
-| [listObjectsV2]         | [copyObject]             |                      | [setBucketPolicy]                       |
-| [listIncompleteUploads] | [statObject]             |                      |                                         |
-|                         | [removeObject]           |                      |                                         |
-|                         | [removeObjects]          |                      |                                         |
-|                         | [removeIncompleteUpload] |                      |                                         |
+| Bucket operations       | Object operations        | Presigned operations  | Bucket Policy & Notification operations |
+| ----------------------- | ------------------------ | --------------------- | --------------------------------------- |
+| [makeBucket]            | [getObject]              | [presignedUrl]        | [getBucketNotification]                 |
+| [listBuckets]           | [getPartialObject]       | [presignedGetObject]  | [setBucketNotification]                 |
+| [bucketExists]          | [fGetObject]             | [presignedPutObject]  | [removeAllBucketNotification]           |
+| [removeBucket]          | [putObject]              | [presignedPostPolicy] | [listenBucketNotification]              |
+| [listObjects]           | [fPutObject]             |                       | [getBucketPolicy]                       |
+| [listObjectsV2]         | [copyObject]             |                       | [setBucketPolicy]                       |
+| [listIncompleteUploads] | [statObject]             |                       |                                         |
+| [listAllObjects]        | [removeObject]           |                       |                                         |
+| [listAllObjectsV2]      | [removeObjects]          |                       |                                         |
+|                         | [removeIncompleteUpload] |                       |                                         |
 
 
 ## Usage
@@ -45,6 +45,17 @@ final minio = Minio(
 );
 ```
 
+**Filebase**
+
+```dart
+final minio = Minio(
+  endPoint: 's3.filebase.com',
+  accessKey: 'YOUR-ACCESSKEYID',
+  secretKey: 'YOUR-SECRETACCESSKEY',
+  useSSL: true,
+);
+```
+
 **File upload**
 ```dart
 import 'package:minio/io.dart';
@@ -109,6 +120,8 @@ MIT
 [listObjects]: https://pub.dev/documentation/minio/latest/minio/Minio/listObjects.html
 [listObjectsV2]: https://pub.dev/documentation/minio/latest/minio/Minio/listObjectsV2.html
 [listIncompleteUploads]: https://pub.dev/documentation/minio/latest/minio/Minio/listIncompleteUploads.html
+[listAllObjects]: https://pub.dev/documentation/minio/latest/minio/Minio/listAllObjects.html
+[listAllObjectsV2]: https://pub.dev/documentation/minio/latest/minio/Minio/listAllObjectsV2.html
 
 [getObject]: https://pub.dev/documentation/minio/latest/minio/Minio/getObject.html
 [getPartialObject]: https://pub.dev/documentation/minio/latest/minio/Minio/getPartialObject.html
diff --git a/example/filebase_example.dart b/example/filebase_example.dart
new file mode 100644
index 0000000000000000000000000000000000000000..76b15201be5d91afbcbe532ebe4d0f35a6dab334
--- /dev/null
+++ b/example/filebase_example.dart
@@ -0,0 +1,16 @@
+import 'package:minio/minio.dart';
+
+void main() async {
+  final minio = Minio(
+    endPoint: 's3.filebase.com',
+    accessKey: '<YOUR_ACCESS_KEY>',
+    secretKey: '<YOUR_SECRET_KEY>',
+    useSSL: true,
+  );
+
+  final buckets = await minio.listBuckets();
+  print('buckets: $buckets');
+
+  final objects = await minio.listObjects(buckets.first.name).toList();
+  print('objects: $objects');
+}
diff --git a/lib/minio.dart b/lib/minio.dart
index c4333be2a8b99daec627e4a6691be798cd1da822..34f8b0e0ed8f62f3af3645681fc83571fc9236fb 100644
--- a/lib/minio.dart
+++ b/lib/minio.dart
@@ -3,5 +3,3 @@ library minio;
 export 'src/minio.dart';
 export 'src/minio_errors.dart';
 export 'src/minio_stream.dart';
-
-// TODO: Export any libraries intended for clients of this package.
diff --git a/lib/src/minio_client.dart b/lib/src/minio_client.dart
index 4287ce59c6685990c7dd1733b5be754f264c60ba..d4045b7ae84700d32ca25d21275b273afa509554 100644
--- a/lib/src/minio_client.dart
+++ b/lib/src/minio_client.dart
@@ -186,16 +186,21 @@ class MinioClient {
       if (object != null) path = '/$bucket/$object';
     }
 
-    final resourcePart = resource == null ? '' : '$resource';
-    final queryPart = queries == null ? '' : '&${encodeQueries(queries)}';
-    final query = resourcePart + queryPart;
+    final query = StringBuffer();
+    if (resource != null) {
+      query.write(resource);
+    }
+    if (queries != null) {
+      if (query.isNotEmpty) query.write('&');
+      query.write(encodeQueries(queries));
+    }
 
     return Uri(
       scheme: minio.useSSL ? 'https' : 'http',
       host: host,
       port: minio.port,
       pathSegments: path.split('/'),
-      query: query,
+      query: query.toString(),
     );
   }
 
diff --git a/lib/src/minio_models.dart b/lib/src/minio_models.dart
index 801ca1d9a2181dd4e357d1c1435c9322c7663a30..f97abaeb7334e358fe1b64ff977161db71326dff 100644
--- a/lib/src/minio_models.dart
+++ b/lib/src/minio_models.dart
@@ -5,14 +5,22 @@ import 'package:xml/xml.dart';
 
 import '../models.dart';
 
-class ListObjectsChunk {
-  ListObjectsChunk({
+class ListObjectsResult {
+  ListObjectsResult({
     required this.objects,
     required this.prefixes,
   });
 
+  /// Metadata about each object returned.
   final List<Object> objects;
-  final List<String?> prefixes;
+
+  /// Like directorys in a file system, prefixes are delimited by slashes.
+  final List<String> prefixes;
+
+  @override
+  String toString() {
+    return 'ListObjectsChunk{objects: $objects, prefixes: $prefixes}';
+  }
 }
 
 class ListObjectsOutput {
diff --git a/lib/src/minio_models_generated.dart b/lib/src/minio_models_generated.dart
index 1e55235a0896efdfcde88f9c45439cc93a716f98..6c98d091f540f91e56cd4722648ccd0104283108 100644
--- a/lib/src/minio_models_generated.dart
+++ b/lib/src/minio_models_generated.dart
@@ -271,9 +271,11 @@ class Bucket {
     this.name,
   );
 
-  Bucket.fromXml(XmlElement xml) {
-    creationDate = DateTime.parse(getProp(xml, 'CreationDate')!.text);
-    name = getProp(xml, 'Name')?.text;
+  factory Bucket.fromXml(XmlElement xml) {
+    return Bucket(
+      DateTime.parse(getProp(xml, 'CreationDate')!.text),
+      getProp(xml, 'Name')!.text,
+    );
   }
 
   XmlNode toXml() {
@@ -289,7 +291,12 @@ class Bucket {
   DateTime? creationDate;
 
   /// The name of the bucket.
-  String? name;
+  String name;
+
+  @override
+  String toString() {
+    return 'Bucket{creationDate: $creationDate, name: $name}';
+  }
 }
 
 /// Specifies the lifecycle configuration for objects in an Amazon S3 bucket. For more information, see Object Lifecycle Management in the Amazon Simple Storage Service Developer Guide.
@@ -1091,6 +1098,11 @@ class Error {
 
   /// The version ID of the error.
   String? versionId;
+
+  @override
+  String toString() {
+    return 'Error{code: $code, key: $key, message: $message, versionId: $versionId}';
+  }
 }
 
 /// The error information.
@@ -2270,6 +2282,11 @@ class Object {
 
   /// The class of storage used to store the object.
   String? storageClass;
+
+  @override
+  String toString() {
+    return 'Object{eTag: $eTag, key: $key, lastModified: $lastModified, owner: $owner, size: $size, storageClass: $storageClass}';
+  }
 }
 
 /// Object Identifier is unique value to identify objects.
diff --git a/test/helpers.dart b/test/helpers.dart
index 63ca1731a16c218e7f236ff6be5f3721977d131d..b0cd2d6a4b0f492f8cff0f6d625d4c565b8e81d2 100644
--- a/test/helpers.dart
+++ b/test/helpers.dart
@@ -1,3 +1,5 @@
+import 'dart:math';
+
 import 'package:minio/minio.dart';
 
 /// Initializes an instance of [Minio] with per default valid configuration.
@@ -24,3 +26,11 @@ Minio getMinioClient({
       region: region,
       enableTrace: enableTrace,
     );
+
+/// Generates a random name for a bucket or object.
+String uniqueName() {
+  final random = Random();
+  final now = DateTime.now();
+  final name = 'id-${now.microsecondsSinceEpoch}-${random.nextInt(8192)}';
+  return name;
+}
diff --git a/test/minio_stream_test.dart b/test/minio_stream_test.dart
index 8c74cd832e9c86339a7769c785307f380f144d02..fbc031c2665dca77c60fe6c36502351220a0ca8b 100644
--- a/test/minio_stream_test.dart
+++ b/test/minio_stream_test.dart
@@ -4,7 +4,7 @@ import 'helpers.dart';
 
 void main() {
   group('MinioByteStream', () {
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
     final objectName = 'content-length-test';
     final testData = [1, 2, 3, 4, 5];
 
diff --git a/test/minio_test.dart b/test/minio_test.dart
index 3f00c45622b7159ea6e560ba4d5661026847f915..f31c88af943ce5bd9fe24d6793dcf1406a751a3d 100644
--- a/test/minio_test.dart
+++ b/test/minio_test.dart
@@ -77,10 +77,10 @@ void testListBuckets() {
 
   test('listBuckets() can list buckets', () async {
     final minio = getMinioClient();
-    final bucketName1 = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName1 = uniqueName();
     await minio.makeBucket(bucketName1);
 
-    final bucketName2 = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName2 = uniqueName();
     await minio.makeBucket(bucketName2);
 
     final buckets = await minio.listBuckets();
@@ -97,10 +97,10 @@ void testListBuckets() {
     expect(
       () async => await minio.listBuckets(),
       throwsA(
-        isA<MinioError>().having(
-          (e) => e.message,
+        isA<MinioS3Error>().having(
+          (e) => e.error!.code,
           'message',
-          'The Access Key Id you provided does not exist in our records.',
+          'AccessDenied',
         ),
       ),
     );
@@ -112,10 +112,10 @@ void testListBuckets() {
     expect(
       () async => await minio.listBuckets(),
       throwsA(
-        isA<MinioError>().having(
-          (e) => e.message,
+        isA<MinioS3Error>().having(
+          (e) => e.error!.code,
           'message',
-          'The request signature we calculated does not match the signature you provided. Check your key and signing method.',
+          'AccessDenied',
         ),
       ),
     );
@@ -124,7 +124,7 @@ void testListBuckets() {
 
 void testBucketExists() {
   group('bucketExists', () {
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     setUpAll(() async {
       final minio = getMinioClient();
@@ -179,7 +179,7 @@ void testBucketExists() {
 
 void testFPutObject() {
   group('fPutObject', () {
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
     late Directory tempDir;
     late File testFile;
     final objectName = 'a.jpg';
@@ -262,7 +262,7 @@ void testSetObjectACL() {
     final objectName = 'a.jpg';
 
     setUpAll(() async {
-      bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+      bucketName = uniqueName();
 
       tempDir = await Directory.systemTemp.createTemp();
       testFile = await File('${tempDir.path}/$objectName').create();
@@ -293,7 +293,7 @@ void testGetObjectACL() {
     final objectName = 'a.jpg';
 
     setUpAll(() async {
-      bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+      bucketName = uniqueName();
 
       tempDir = await Directory.systemTemp.createTemp();
       testFile = await File('${tempDir.path}/$objectName').create();
@@ -320,8 +320,8 @@ void testGetObjectACL() {
 void testGetObject() {
   group('getObject()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
-    final objectName = DateTime.now().microsecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
+    final objectName = uniqueName();
     final objectData = Uint8List.fromList([1, 2, 3]);
 
     setUpAll(() async {
@@ -361,7 +361,7 @@ void testGetObject() {
 void testPutObject() {
   group('putObject()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
     final objectData = Uint8List.fromList([1, 2, 3]);
 
     setUpAll(() async {
@@ -373,7 +373,7 @@ void testPutObject() {
     });
 
     test('succeeds', () async {
-      final objectName = DateTime.now().microsecondsSinceEpoch.toString();
+      final objectName = uniqueName();
       await minio.putObject(bucketName, objectName, Stream.value(objectData));
       final stat = await minio.statObject(bucketName, objectName);
       expect(stat.size, equals(objectData.length));
@@ -381,8 +381,7 @@ void testPutObject() {
     });
 
     test('works with object names with symbols', () async {
-      final objectName =
-          DateTime.now().microsecondsSinceEpoch.toString() + r'-._~,!@#$%^&*()';
+      final objectName = uniqueName() + r'-._~,!@#$%^&*()';
       await minio.putObject(bucketName, objectName, Stream.value(objectData));
       final stat = await minio.statObject(bucketName, objectName);
       expect(stat.size, equals(objectData.length));
@@ -394,7 +393,7 @@ void testPutObject() {
 void testGetBucketNotification() {
   group('getBucketNotification()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     setUpAll(() async {
       await minio.makeBucket(bucketName);
@@ -413,7 +412,7 @@ void testGetBucketNotification() {
 void testSetBucketNotification() {
   group('setBucketNotification()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     setUpAll(() async {
       await minio.makeBucket(bucketName);
@@ -435,7 +434,7 @@ void testSetBucketNotification() {
 void testRemoveAllBucketNotification() {
   group('removeAllBucketNotification()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     setUpAll(() async {
       await minio.makeBucket(bucketName);
@@ -454,8 +453,8 @@ void testRemoveAllBucketNotification() {
 void testListenBucketNotification() {
   group('listenBucketNotification()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
-    // final objectName = DateTime.now().microsecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
+    // final objectName = uniqueName();
 
     setUpAll(() async {
       await minio.makeBucket(bucketName);
@@ -495,8 +494,8 @@ void testListenBucketNotification() {
 void testStatObject() {
   group('statObject()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
-    final objectName = DateTime.now().microsecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
+    final objectName = uniqueName();
     final data = [1, 2, 3, 4, 5];
 
     setUpAll(() async {
@@ -536,7 +535,7 @@ void testStatObject() {
 void testMakeBucket() {
   group('makeBucket()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     setUpAll(() async {
       await minio.makeBucket(bucketName);
@@ -557,7 +556,7 @@ void testMakeBucket() {
 void testRemoveBucket() {
   group('removeBucket()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
 
     test('succeeds', () async {
       await minio.makeBucket(bucketName);
@@ -576,8 +575,8 @@ void testRemoveBucket() {
 void testRemoveObject() {
   group('removeObject()', () {
     final minio = getMinioClient();
-    final bucketName = DateTime.now().millisecondsSinceEpoch.toString();
-    final objectName = DateTime.now().microsecondsSinceEpoch.toString();
+    final bucketName = uniqueName();
+    final objectName = uniqueName();
     final data = [1, 2, 3, 4, 5];
 
     setUpAll(() async {