miso-client 0.4.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of miso-client might be problematic. Click here for more details.

Files changed (45) hide show
  1. {miso_client-0.4.0 → miso_client-0.5.0}/CHANGELOG.md +87 -0
  2. {miso_client-0.4.0/miso_client.egg-info → miso_client-0.5.0}/PKG-INFO +220 -1
  3. {miso_client-0.4.0 → miso_client-0.5.0}/README.md +219 -0
  4. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/__init__.py +39 -1
  5. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/models/error_response.py +10 -1
  6. miso_client-0.5.0/miso_client/models/filter.py +140 -0
  7. miso_client-0.5.0/miso_client/models/pagination.py +66 -0
  8. miso_client-0.5.0/miso_client/models/sort.py +25 -0
  9. miso_client-0.5.0/miso_client/utils/error_utils.py +104 -0
  10. miso_client-0.5.0/miso_client/utils/filter.py +256 -0
  11. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/http_client.py +107 -0
  12. miso_client-0.5.0/miso_client/utils/pagination.py +157 -0
  13. miso_client-0.5.0/miso_client/utils/sort.py +116 -0
  14. {miso_client-0.4.0 → miso_client-0.5.0/miso_client.egg-info}/PKG-INFO +220 -1
  15. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client.egg-info/SOURCES.txt +8 -1
  16. {miso_client-0.4.0 → miso_client-0.5.0}/pyproject.toml +1 -1
  17. {miso_client-0.4.0 → miso_client-0.5.0}/setup.py +1 -1
  18. {miso_client-0.4.0 → miso_client-0.5.0}/LICENSE +0 -0
  19. {miso_client-0.4.0 → miso_client-0.5.0}/MANIFEST.in +0 -0
  20. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/errors.py +0 -0
  21. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/models/__init__.py +0 -0
  22. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/models/config.py +0 -0
  23. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/py.typed +0 -0
  24. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/__init__.py +0 -0
  25. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/auth.py +0 -0
  26. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/cache.py +0 -0
  27. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/encryption.py +0 -0
  28. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/logger.py +0 -0
  29. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/permission.py +0 -0
  30. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/redis.py +0 -0
  31. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/services/role.py +0 -0
  32. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/__init__.py +0 -0
  33. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/config_loader.py +0 -0
  34. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/data_masker.py +0 -0
  35. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/internal_http_client.py +0 -0
  36. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/jwt_tools.py +0 -0
  37. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client/utils/sensitive_fields_loader.py +0 -0
  38. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client.egg-info/dependency_links.txt +0 -0
  39. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client.egg-info/not-zip-safe +0 -0
  40. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client.egg-info/requires.txt +0 -0
  41. {miso_client-0.4.0 → miso_client-0.5.0}/miso_client.egg-info/top_level.txt +0 -0
  42. {miso_client-0.4.0 → miso_client-0.5.0}/pytest.ini +0 -0
  43. {miso_client-0.4.0 → miso_client-0.5.0}/requirements-test.txt +0 -0
  44. {miso_client-0.4.0 → miso_client-0.5.0}/requirements.txt +0 -0
  45. {miso_client-0.4.0 → miso_client-0.5.0}/setup.cfg +0 -0
@@ -5,6 +5,93 @@ All notable changes to the MisoClient SDK will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.0] - 2025-11-02
9
+
10
+ ### Added
11
+
12
+ - **Pagination Utilities**: Complete pagination support for list responses
13
+ - `Meta` and `PaginatedListResponse` Pydantic models for standardized paginated responses
14
+ - `parse_pagination_params()` function to parse `page` and `page_size` query parameters
15
+ - `create_meta_object()` function to construct pagination metadata objects
16
+ - `apply_pagination_to_array()` function for local pagination in tests/mocks
17
+ - `create_paginated_list_response()` function to wrap data with pagination metadata
18
+ - Support for both snake_case (`total_items`, `current_page`, `page_size`) and camelCase (`totalItems`, `currentPage`, `pageSize`) attribute access
19
+ - Full type safety with Pydantic models and generic type support
20
+
21
+ - **Filtering Utilities**: Comprehensive filtering support for API queries
22
+ - `FilterOption`, `FilterQuery`, and `FilterBuilder` classes for building filter queries
23
+ - `FilterOperator` type supporting: `eq`, `neq`, `in`, `nin`, `gt`, `lt`, `gte`, `lte`, `contains`, `like`
24
+ - `parse_filter_params()` function to parse `filter=field:op:value` query parameters
25
+ - `build_query_string()` function to convert `FilterQuery` objects to URL query strings
26
+ - `apply_filters()` function for local filtering in tests/mocks
27
+ - `FilterBuilder` class with fluent API for method chaining (e.g., `FilterBuilder().add('status', 'eq', 'active').add('region', 'in', ['eu', 'us'])`)
28
+ - URL encoding support for field names and values (comma separators preserved for array values)
29
+ - Integration with `/metadata/filter` endpoint through `FilterBuilder` compatibility with `AccessFieldFilter`
30
+
31
+ - **Sorting Utilities**: Sort parameter parsing and building
32
+ - `SortOption` Pydantic model with `field` and `order` (asc/desc) properties
33
+ - `parse_sort_params()` function to parse `sort=-field` query parameters
34
+ - `build_sort_string()` function to convert `SortOption` lists to query string format
35
+ - Support for multiple sort fields with ascending/descending order
36
+ - URL encoding for field names with special characters
37
+
38
+ - **Error Handling Utilities**: Enhanced error response transformation and handling
39
+ - `transform_error_to_snake_case()` function for converting error dictionaries to `ErrorResponse` objects
40
+ - `handle_api_error_snake_case()` function for creating `MisoClientError` from API error responses
41
+ - Support for both camelCase and snake_case field names in error responses
42
+ - Automatic parameter overriding (instance and status_code parameters override response data)
43
+ - Graceful handling of missing optional fields (title, instance, request_key)
44
+
45
+ - **HTTP Client Enhancements**: New helper methods for filtered and paginated requests
46
+ - `get_with_filters()` method for making GET requests with `FilterBuilder` support
47
+ - `get_paginated()` method for making GET requests with pagination parameters
48
+ - Automatic query string building from filter/sort/pagination options
49
+ - Flexible response parsing (returns `PaginatedListResponse` when format matches, raw response otherwise)
50
+
51
+ - **ErrorResponse Model Enhancements**:
52
+ - Added `request_key` field for error tracking (supports both `request_key` and `requestKey` aliases)
53
+ - Made `title` field optional (defaults to `None`) for graceful handling of missing titles
54
+ - Added `status_code` property getter for snake_case access (complements `statusCode` camelCase field)
55
+ - Full support for both snake_case and camelCase attribute access
56
+
57
+ - **Model Exports**: All new models and utilities exported from main module
58
+ - Pagination: `Meta`, `PaginatedListResponse`, `parse_pagination_params`, `create_meta_object`, `apply_pagination_to_array`, `create_paginated_list_response`
59
+ - Filtering: `FilterOperator`, `FilterOption`, `FilterQuery`, `FilterBuilder`, `parse_filter_params`, `build_query_string`, `apply_filters`
60
+ - Sorting: `SortOption`, `parse_sort_params`, `build_sort_string`
61
+ - Error: `transform_error_to_snake_case`, `handle_api_error_snake_case`
62
+ - All utilities follow snake_case naming convention matching Miso/Dataplane API conventions
63
+
64
+ ### Changed
65
+
66
+ - **ErrorResponse Model**: Made `title` field optional to support APIs that don't provide titles
67
+ - Old: `title: str = Field(..., description="Human-readable error title")`
68
+ - New: `title: Optional[str] = Field(default=None, description="Human-readable error title")`
69
+ - Backward compatible - existing code with required titles still works
70
+
71
+ - **handle_api_error_snake_case Function**: Enhanced parameter override behavior
72
+ - `instance` parameter now overrides instance in response_data (was only set if missing)
73
+ - `status_code` parameter now always overrides status_code in response_data (was only set if missing)
74
+ - Better error message generation when title is missing
75
+
76
+ ### Technical Improvements
77
+
78
+ - **Type Safety**: Full type hints throughout all new utilities and models
79
+ - **Pydantic Models**: All new data structures use Pydantic for validation and serialization
80
+ - **Property Getters**: Added property getters to support both snake_case and camelCase attribute access in models
81
+ - **URL Encoding**: Smart encoding that preserves comma delimiters in array filter values
82
+ - **Comprehensive Tests**: 123 unit tests covering all utilities with 100% coverage for models and utilities
83
+ - **Documentation**: Complete README documentation with usage examples for all utilities
84
+ - **Snake_case Convention**: All utilities follow Python snake_case naming to match Miso/Dataplane API conventions
85
+
86
+ ### Documentation
87
+
88
+ - Added comprehensive README section for pagination, filtering, and sorting utilities
89
+ - Usage examples for all utilities including combined usage patterns
90
+ - Integration examples with `/metadata/filter` endpoint
91
+ - Type hints and docstrings for all public APIs
92
+
93
+ ---
94
+
8
95
  ## [0.4.0] - 2025-11-02
9
96
 
10
97
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: miso-client
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Python client SDK for AI Fabrix authentication, authorization, and logging
5
5
  Home-page: https://github.com/aifabrix/miso-client-python
6
6
  Author: AI Fabrix Team
@@ -611,6 +611,225 @@ print(error_response.statusCode) # 422
611
611
  print(error_response.instance) # "/api/endpoint"
612
612
  ```
613
613
 
614
+ ---
615
+
616
+ ### Pagination, Filtering, and Sorting Utilities
617
+
618
+ **What happens:** The SDK provides reusable utilities for pagination, filtering, sorting, and error handling that work with any API endpoint.
619
+
620
+ #### Pagination
621
+
622
+ **Pagination Parameters:**
623
+ - `page`: Page number (1-based, defaults to 1)
624
+ - `page_size`: Number of items per page (defaults to 25)
625
+
626
+ ```python
627
+ from miso_client import (
628
+ parse_pagination_params,
629
+ create_paginated_list_response,
630
+ PaginatedListResponse,
631
+ )
632
+
633
+ # Parse pagination from query parameters
634
+ params = {"page": "1", "page_size": "25"}
635
+ current_page, page_size = parse_pagination_params(params)
636
+
637
+ # Create paginated response
638
+ items = [{"id": 1}, {"id": 2}]
639
+ response = create_paginated_list_response(
640
+ items,
641
+ total_items=120,
642
+ current_page=1,
643
+ page_size=25,
644
+ type="item"
645
+ )
646
+
647
+ # Response structure:
648
+ # {
649
+ # "meta": {
650
+ # "total_items": 120,
651
+ # "current_page": 1,
652
+ # "page_size": 25,
653
+ # "type": "item"
654
+ # },
655
+ # "data": [{"id": 1}, {"id": 2}]
656
+ # }
657
+ ```
658
+
659
+ #### Filtering
660
+
661
+ **Filter Operators:** `eq`, `neq`, `in`, `nin`, `gt`, `lt`, `gte`, `lte`, `contains`, `like`
662
+
663
+ **Filter Format:** `field:op:value` (e.g., `status:eq:active`)
664
+
665
+ ```python
666
+ from miso_client import FilterBuilder, parse_filter_params, build_query_string
667
+
668
+ # Dynamic filter building with FilterBuilder
669
+ filter_builder = FilterBuilder() \
670
+ .add('status', 'eq', 'active') \
671
+ .add('region', 'in', ['eu', 'us']) \
672
+ .add('created_at', 'gte', '2024-01-01')
673
+
674
+ # Get query string
675
+ query_string = filter_builder.to_query_string()
676
+ # Returns: "filter=status:eq:active&filter=region:in:eu,us&filter=created_at:gte:2024-01-01"
677
+
678
+ # Parse existing filter parameters
679
+ params = {'filter': ['status:eq:active', 'region:in:eu,us']}
680
+ filters = parse_filter_params(params)
681
+ # Returns: [FilterOption(field='status', op='eq', value='active'), ...]
682
+
683
+ # Use with HTTP client
684
+ response = await client.http_client.get_with_filters(
685
+ '/api/items',
686
+ filter_builder=filter_builder
687
+ )
688
+ ```
689
+
690
+ **Building Complete Filter Queries:**
691
+
692
+ ```python
693
+ from miso_client import FilterQuery, FilterOption, build_query_string
694
+
695
+ # Create filter query with filters, sort, pagination, and fields
696
+ filter_query = FilterQuery(
697
+ filters=[
698
+ FilterOption(field='status', op='eq', value='active'),
699
+ FilterOption(field='region', op='in', value=['eu', 'us'])
700
+ ],
701
+ sort=['-updated_at', 'created_at'],
702
+ page=1,
703
+ page_size=25,
704
+ fields=['id', 'name', 'status']
705
+ )
706
+
707
+ # Build query string
708
+ query_string = build_query_string(filter_query)
709
+ ```
710
+
711
+ #### Sorting
712
+
713
+ **Sort Format:** `-field` for descending, `field` for ascending (e.g., `-updated_at`, `created_at`)
714
+
715
+ ```python
716
+ from miso_client import parse_sort_params, build_sort_string, SortOption
717
+
718
+ # Parse sort parameters
719
+ params = {'sort': '-updated_at'}
720
+ sort_options = parse_sort_params(params)
721
+ # Returns: [SortOption(field='updated_at', order='desc')]
722
+
723
+ # Parse multiple sorts
724
+ params = {'sort': ['-updated_at', 'created_at']}
725
+ sort_options = parse_sort_params(params)
726
+ # Returns: [
727
+ # SortOption(field='updated_at', order='desc'),
728
+ # SortOption(field='created_at', order='asc')
729
+ # ]
730
+
731
+ # Build sort string
732
+ sort_options = [
733
+ SortOption(field='updated_at', order='desc'),
734
+ SortOption(field='created_at', order='asc')
735
+ ]
736
+ sort_string = build_sort_string(sort_options)
737
+ # Returns: "-updated_at,created_at"
738
+ ```
739
+
740
+ #### Combined Usage
741
+
742
+ **Pagination + Filter + Sort:**
743
+
744
+ ```python
745
+ from miso_client import (
746
+ FilterBuilder,
747
+ FilterQuery,
748
+ build_query_string,
749
+ parse_pagination_params,
750
+ )
751
+
752
+ # Build filters
753
+ filter_builder = FilterBuilder() \
754
+ .add('status', 'eq', 'active') \
755
+ .add('region', 'in', ['eu', 'us'])
756
+
757
+ # Parse pagination
758
+ params = {'page': '1', 'page_size': '25'}
759
+ current_page, page_size = parse_pagination_params(params)
760
+
761
+ # Create complete query
762
+ filter_query = FilterQuery(
763
+ filters=filter_builder.build(),
764
+ sort=['-updated_at'],
765
+ page=current_page,
766
+ page_size=page_size
767
+ )
768
+
769
+ # Build query string
770
+ query_string = build_query_string(filter_query)
771
+
772
+ # Use with HTTP client
773
+ response = await client.http_client.get_with_filters(
774
+ '/api/items',
775
+ filter_builder=filter_builder,
776
+ params={'page': current_page, 'page_size': page_size}
777
+ )
778
+ ```
779
+
780
+ **Or use pagination helper:**
781
+
782
+ ```python
783
+ # Get paginated response
784
+ response = await client.http_client.get_paginated(
785
+ '/api/items',
786
+ page=1,
787
+ page_size=25
788
+ )
789
+
790
+ # Response is automatically parsed as PaginatedListResponse
791
+ print(response.meta.total_items) # 120
792
+ print(response.meta.current_page) # 1
793
+ print(len(response.data)) # 25
794
+ ```
795
+
796
+ #### Metadata Filter Integration
797
+
798
+ **Working with `/metadata/filter` endpoint:**
799
+
800
+ ```python
801
+ # Get metadata filters from endpoint
802
+ metadata_response = await client.http_client.post(
803
+ "/api/v1/metadata/filter",
804
+ {"documentStorageKey": "my-doc-storage"}
805
+ )
806
+
807
+ # Convert AccessFieldFilter to FilterBuilder
808
+ filter_builder = FilterBuilder()
809
+ for access_filter in metadata_response.mandatoryFilters:
810
+ filter_builder.add(access_filter.field, 'in', access_filter.values)
811
+
812
+ # Use with query utilities
813
+ query_string = filter_builder.to_query_string()
814
+
815
+ # Apply to API requests
816
+ response = await client.http_client.get_with_filters(
817
+ '/api/items',
818
+ filter_builder=filter_builder
819
+ )
820
+ ```
821
+
822
+ **Features:**
823
+
824
+ - **Snake_case Convention**: All utilities use snake_case to match Miso/Dataplane API
825
+ - **Type Safety**: Full type hints with Pydantic models
826
+ - **Dynamic Filtering**: FilterBuilder supports method chaining for complex filters
827
+ - **Local Testing**: `apply_filters()` and `apply_pagination_to_array()` for local filtering/pagination in tests
828
+ - **URL Encoding**: Automatic URL encoding for field names and values
829
+ - **Backward Compatible**: Works alongside existing HTTP client methods
830
+
831
+ ---
832
+
614
833
  ### Common Tasks
615
834
 
616
835
  **Add authentication middleware (FastAPI):**
@@ -562,6 +562,225 @@ print(error_response.statusCode) # 422
562
562
  print(error_response.instance) # "/api/endpoint"
563
563
  ```
564
564
 
565
+ ---
566
+
567
+ ### Pagination, Filtering, and Sorting Utilities
568
+
569
+ **What happens:** The SDK provides reusable utilities for pagination, filtering, sorting, and error handling that work with any API endpoint.
570
+
571
+ #### Pagination
572
+
573
+ **Pagination Parameters:**
574
+ - `page`: Page number (1-based, defaults to 1)
575
+ - `page_size`: Number of items per page (defaults to 25)
576
+
577
+ ```python
578
+ from miso_client import (
579
+ parse_pagination_params,
580
+ create_paginated_list_response,
581
+ PaginatedListResponse,
582
+ )
583
+
584
+ # Parse pagination from query parameters
585
+ params = {"page": "1", "page_size": "25"}
586
+ current_page, page_size = parse_pagination_params(params)
587
+
588
+ # Create paginated response
589
+ items = [{"id": 1}, {"id": 2}]
590
+ response = create_paginated_list_response(
591
+ items,
592
+ total_items=120,
593
+ current_page=1,
594
+ page_size=25,
595
+ type="item"
596
+ )
597
+
598
+ # Response structure:
599
+ # {
600
+ # "meta": {
601
+ # "total_items": 120,
602
+ # "current_page": 1,
603
+ # "page_size": 25,
604
+ # "type": "item"
605
+ # },
606
+ # "data": [{"id": 1}, {"id": 2}]
607
+ # }
608
+ ```
609
+
610
+ #### Filtering
611
+
612
+ **Filter Operators:** `eq`, `neq`, `in`, `nin`, `gt`, `lt`, `gte`, `lte`, `contains`, `like`
613
+
614
+ **Filter Format:** `field:op:value` (e.g., `status:eq:active`)
615
+
616
+ ```python
617
+ from miso_client import FilterBuilder, parse_filter_params, build_query_string
618
+
619
+ # Dynamic filter building with FilterBuilder
620
+ filter_builder = FilterBuilder() \
621
+ .add('status', 'eq', 'active') \
622
+ .add('region', 'in', ['eu', 'us']) \
623
+ .add('created_at', 'gte', '2024-01-01')
624
+
625
+ # Get query string
626
+ query_string = filter_builder.to_query_string()
627
+ # Returns: "filter=status:eq:active&filter=region:in:eu,us&filter=created_at:gte:2024-01-01"
628
+
629
+ # Parse existing filter parameters
630
+ params = {'filter': ['status:eq:active', 'region:in:eu,us']}
631
+ filters = parse_filter_params(params)
632
+ # Returns: [FilterOption(field='status', op='eq', value='active'), ...]
633
+
634
+ # Use with HTTP client
635
+ response = await client.http_client.get_with_filters(
636
+ '/api/items',
637
+ filter_builder=filter_builder
638
+ )
639
+ ```
640
+
641
+ **Building Complete Filter Queries:**
642
+
643
+ ```python
644
+ from miso_client import FilterQuery, FilterOption, build_query_string
645
+
646
+ # Create filter query with filters, sort, pagination, and fields
647
+ filter_query = FilterQuery(
648
+ filters=[
649
+ FilterOption(field='status', op='eq', value='active'),
650
+ FilterOption(field='region', op='in', value=['eu', 'us'])
651
+ ],
652
+ sort=['-updated_at', 'created_at'],
653
+ page=1,
654
+ page_size=25,
655
+ fields=['id', 'name', 'status']
656
+ )
657
+
658
+ # Build query string
659
+ query_string = build_query_string(filter_query)
660
+ ```
661
+
662
+ #### Sorting
663
+
664
+ **Sort Format:** `-field` for descending, `field` for ascending (e.g., `-updated_at`, `created_at`)
665
+
666
+ ```python
667
+ from miso_client import parse_sort_params, build_sort_string, SortOption
668
+
669
+ # Parse sort parameters
670
+ params = {'sort': '-updated_at'}
671
+ sort_options = parse_sort_params(params)
672
+ # Returns: [SortOption(field='updated_at', order='desc')]
673
+
674
+ # Parse multiple sorts
675
+ params = {'sort': ['-updated_at', 'created_at']}
676
+ sort_options = parse_sort_params(params)
677
+ # Returns: [
678
+ # SortOption(field='updated_at', order='desc'),
679
+ # SortOption(field='created_at', order='asc')
680
+ # ]
681
+
682
+ # Build sort string
683
+ sort_options = [
684
+ SortOption(field='updated_at', order='desc'),
685
+ SortOption(field='created_at', order='asc')
686
+ ]
687
+ sort_string = build_sort_string(sort_options)
688
+ # Returns: "-updated_at,created_at"
689
+ ```
690
+
691
+ #### Combined Usage
692
+
693
+ **Pagination + Filter + Sort:**
694
+
695
+ ```python
696
+ from miso_client import (
697
+ FilterBuilder,
698
+ FilterQuery,
699
+ build_query_string,
700
+ parse_pagination_params,
701
+ )
702
+
703
+ # Build filters
704
+ filter_builder = FilterBuilder() \
705
+ .add('status', 'eq', 'active') \
706
+ .add('region', 'in', ['eu', 'us'])
707
+
708
+ # Parse pagination
709
+ params = {'page': '1', 'page_size': '25'}
710
+ current_page, page_size = parse_pagination_params(params)
711
+
712
+ # Create complete query
713
+ filter_query = FilterQuery(
714
+ filters=filter_builder.build(),
715
+ sort=['-updated_at'],
716
+ page=current_page,
717
+ page_size=page_size
718
+ )
719
+
720
+ # Build query string
721
+ query_string = build_query_string(filter_query)
722
+
723
+ # Use with HTTP client
724
+ response = await client.http_client.get_with_filters(
725
+ '/api/items',
726
+ filter_builder=filter_builder,
727
+ params={'page': current_page, 'page_size': page_size}
728
+ )
729
+ ```
730
+
731
+ **Or use pagination helper:**
732
+
733
+ ```python
734
+ # Get paginated response
735
+ response = await client.http_client.get_paginated(
736
+ '/api/items',
737
+ page=1,
738
+ page_size=25
739
+ )
740
+
741
+ # Response is automatically parsed as PaginatedListResponse
742
+ print(response.meta.total_items) # 120
743
+ print(response.meta.current_page) # 1
744
+ print(len(response.data)) # 25
745
+ ```
746
+
747
+ #### Metadata Filter Integration
748
+
749
+ **Working with `/metadata/filter` endpoint:**
750
+
751
+ ```python
752
+ # Get metadata filters from endpoint
753
+ metadata_response = await client.http_client.post(
754
+ "/api/v1/metadata/filter",
755
+ {"documentStorageKey": "my-doc-storage"}
756
+ )
757
+
758
+ # Convert AccessFieldFilter to FilterBuilder
759
+ filter_builder = FilterBuilder()
760
+ for access_filter in metadata_response.mandatoryFilters:
761
+ filter_builder.add(access_filter.field, 'in', access_filter.values)
762
+
763
+ # Use with query utilities
764
+ query_string = filter_builder.to_query_string()
765
+
766
+ # Apply to API requests
767
+ response = await client.http_client.get_with_filters(
768
+ '/api/items',
769
+ filter_builder=filter_builder
770
+ )
771
+ ```
772
+
773
+ **Features:**
774
+
775
+ - **Snake_case Convention**: All utilities use snake_case to match Miso/Dataplane API
776
+ - **Type Safety**: Full type hints with Pydantic models
777
+ - **Dynamic Filtering**: FilterBuilder supports method chaining for complex filters
778
+ - **Local Testing**: `apply_filters()` and `apply_pagination_to_array()` for local filtering/pagination in tests
779
+ - **URL Encoding**: Automatic URL encoding for field names and values
780
+ - **Backward Compatible**: Works alongside existing HTTP client methods
781
+
782
+ ---
783
+
565
784
  ### Common Tasks
566
785
 
567
786
  **Add authentication middleware (FastAPI):**
@@ -27,6 +27,9 @@ from .models.config import (
27
27
  UserInfo,
28
28
  )
29
29
  from .models.error_response import ErrorResponse
30
+ from .models.filter import FilterBuilder, FilterOperator, FilterOption, FilterQuery
31
+ from .models.pagination import Meta, PaginatedListResponse
32
+ from .models.sort import SortOption
30
33
  from .services.auth import AuthService
31
34
  from .services.cache import CacheService
32
35
  from .services.encryption import EncryptionService
@@ -35,10 +38,19 @@ from .services.permission import PermissionService
35
38
  from .services.redis import RedisService
36
39
  from .services.role import RoleService
37
40
  from .utils.config_loader import load_config
41
+ from .utils.error_utils import handle_api_error_snake_case, transform_error_to_snake_case
42
+ from .utils.filter import apply_filters, build_query_string, parse_filter_params
38
43
  from .utils.http_client import HttpClient
39
44
  from .utils.internal_http_client import InternalHttpClient
45
+ from .utils.pagination import (
46
+ apply_pagination_to_array,
47
+ create_meta_object,
48
+ create_paginated_list_response,
49
+ parse_pagination_params,
50
+ )
51
+ from .utils.sort import build_sort_string, parse_sort_params
40
52
 
41
- __version__ = "0.4.0"
53
+ __version__ = "0.5.0"
42
54
  __author__ = "AI Fabrix Team"
43
55
  __license__ = "MIT"
44
56
 
@@ -491,6 +503,32 @@ __all__ = [
491
503
  "PerformanceMetrics",
492
504
  "ClientLoggingOptions",
493
505
  "ErrorResponse",
506
+ # Pagination models
507
+ "Meta",
508
+ "PaginatedListResponse",
509
+ # Filter models
510
+ "FilterOperator",
511
+ "FilterOption",
512
+ "FilterQuery",
513
+ "FilterBuilder",
514
+ # Sort models
515
+ "SortOption",
516
+ # Pagination utilities
517
+ "parse_pagination_params",
518
+ "create_meta_object",
519
+ "apply_pagination_to_array",
520
+ "create_paginated_list_response",
521
+ # Filter utilities
522
+ "parse_filter_params",
523
+ "build_query_string",
524
+ "apply_filters",
525
+ # Sort utilities
526
+ "parse_sort_params",
527
+ "build_sort_string",
528
+ # Error utilities
529
+ "transform_error_to_snake_case",
530
+ "handle_api_error_snake_case",
531
+ # Services
494
532
  "AuthService",
495
533
  "RoleService",
496
534
  "PermissionService",
@@ -33,9 +33,18 @@ class ErrorResponse(BaseModel):
33
33
 
34
34
  errors: List[str] = Field(..., description="List of error messages")
35
35
  type: str = Field(..., description="Error type URI (e.g., '/Errors/Bad Input')")
36
- title: str = Field(..., description="Human-readable error title")
36
+ title: Optional[str] = Field(default=None, description="Human-readable error title")
37
37
  statusCode: int = Field(..., alias="status_code", description="HTTP status code")
38
38
  instance: Optional[str] = Field(default=None, description="Request instance URI")
39
+ request_key: Optional[str] = Field(
40
+ default=None, alias="requestKey", description="Request key for error tracking"
41
+ )
39
42
 
40
43
  class Config:
41
44
  populate_by_name = True # Allow both camelCase and snake_case
45
+
46
+ # Support snake_case attribute access
47
+ @property
48
+ def status_code(self) -> int:
49
+ """Get statusCode as status_code (snake_case)."""
50
+ return self.statusCode