BriteCore SDK v2.0.0 Roadmap
Last updated: July 16, 2026 Status: Planning & Implementation
Overview
v2.0.0 introduces breaking changes focused on moving away from implicit global state, improving type safety, standardizing error handling, and providing better extensibility. These changes align with modern Python SDK best practices.
Breaking Changes & Migration Path
Phase 1: Client Lifecycle Redesign
Goal: Move away from module-global implicit client state; make explicit client instances the default API.
Current State (legacy)
# Implicit global client - hard to test, unclear dependencies
from britecore_sdk.api.api_calls import retrieve_quote
quote = retrieve_quote(quote_number="Q123")
# Or explicit but cumbersome
from britecore_sdk.api.api_calls import use_api_client, retrieve_quote
client = BritecoreAPIClient("site").init_client()
with use_api_client(client):
quote = retrieve_quote(quote_number="Q123")
v2.0.0 Target
# Explicit client is now primary pattern
from britecore_sdk import BritecoreAPIClient
from britecore_sdk.api.api_calls.v2 import quotes
client = BritecoreAPIClient("site").init_client()
quote = quotes.retrieve_quote(quote_number="Q123", client=client)
# Or with context manager (preferred for cleanup)
with BritecoreAPIClient("site").init_client() as client:
quote = quotes.retrieve_quote(quote_number="Q123", client=client)
Implementation Strategy
Add optional
clientparameter to all endpoint wrappersFall back to module-level client if not provided (for backwards compatibility during transition)
Deprecate implicit client in a minor release (after initial rollout)
Remove implicit client fallback in v2.0.0
Update all examples to use explicit client pattern
Add type hints for client parameter (remove
Unpack[RequestParameters]anti-pattern)
Acceptance Criteria
[ ] All v2 endpoint wrappers accept optional
client: BritecoreAPIClientparameter[ ] Wrappers prefer explicit client over module-level client
[ ] Examples use explicit client pattern throughout
[ ] Migration guide covers the transition
Phase 2: Typed Response Models
Goal: Reduce Any returns; provide typed response models (or typed envelopes) for sync + async parity.
Current State (legacy)
# Returns `Any` - no IDE autocomplete, runtime surprises
result = retrieve_quote(quote_number="Q123")
quote_premium = result.get("premium") # Could be anything!
# Types are unclear in async too
result = await aretrieve_quote(quote_number="Q123") # Same Any return
v2.0.0 Target
# Typed response models with autocomplete
from britecore_sdk.api.responses import QuoteResponse
from britecore_sdk.api.api_calls.v2 import quotes
quote: QuoteResponse = quotes.retrieve_quote(quote_number="Q123", client=client)
quote_premium = quote.premium # Type-safe, IDE autocomplete
# Async has parity
quote: QuoteResponse = await quotes.aretrieve_quote(quote_number="Q123", client=client)
Response Model Structure
# britecore_sdk/api/responses/__init__.py
from dataclasses import dataclass
from typing import Any, Optional
@dataclass
class ResponseEnvelope:
"""Base envelope for all API responses."""
success: bool
data: Any # The actual typed model
message: Optional[str] = None
messages: Optional[list[str]] = None
request_id: str = "" # Extracted from response headers
status_code: int = 200
@dataclass
class QuoteResponse:
"""Typed response for quote retrieval."""
quote_id: str
quote_number: str
status: str
premium: float
term_days: int
effective_date: str
# ... other fields
@classmethod
def from_api(cls, data: dict) -> "QuoteResponse":
"""Parse API response dict into typed model."""
return cls(
quote_id=data.get("id"),
quote_number=data.get("quoteNumber"),
# ...
)
Implementation Strategy
Define response models for each domain (quotes, policies, contacts, etc.)
Use
dataclassorpydanticBaseModel for runtime validation (opt-in)Create factory methods (
.from_api()) to hydrate models from API responsesUpdate all wrappers to return typed models instead of raw dicts/Any
Maintain backwards compatibility shim (legacy paths continue returning dict/Any)
Provide both
ResponseEnvelopeand direct typed models for flexibility
Acceptance Criteria
[ ] Response models defined for all major domains (quotes, policies, contacts, etc.)
[ ] All v2 wrappers return typed models (not
Anyordict)[ ] Async wrappers return same types as sync equivalents
[ ] Response models support
.from_api()factory pattern[x] Pydantic validation available (opt-in via
britecore_sdk[typed-config]extra; seebritecore_sdk.settings.get_typed_settings()for the settings view)[ ] Full pydantic response models for API payloads (not yet implemented)
[ ] Type stubs (
.pyi) generated or provided for IDE support
Phase 3: Standardized Error Model
Goal: Standardize exceptions with status_code, error_code, request_id, and raw payload attached.
Current State (legacy)
# Error details scattered across exception message
try:
retrieve_quote(quote_number="Q123")
except AuthenticationError as e:
print(str(e)) # Message only, no structured data
# No access to HTTP status, error code, or request ID
v2.0.0 Target
# Rich exception context
from britecore_sdk.exceptions import NotFoundError, ValidationError
try:
retrieve_quote(quote_number="INVALID")
except NotFoundError as e:
print(e.status_code) # 404
print(e.error_code) # "quote_not_found"
print(e.request_id) # "abc123def456"
print(e.detail) # "Quote INVALID does not exist"
print(e.raw_payload) # Full server response dict
except ValidationError as e:
print(e.status_code) # 400
print(e.error_code) # "invalid_field"
print(e.validation_errors) # {"premium": ["Must be positive"]}
Exception Hierarchy (v2.0.0)
class BritecoreError(Exception):
"""Base exception - now with structured metadata."""
status_code: int
error_code: Optional[str]
request_id: Optional[str]
detail: str
raw_payload: dict
def __init__(
self,
detail: str,
status_code: int = 500,
error_code: Optional[str] = None,
request_id: Optional[str] = None,
raw_payload: Optional[dict] = None,
):
self.detail = detail
self.status_code = status_code
self.error_code = error_code
self.request_id = request_id
self.raw_payload = raw_payload or {}
super().__init__(detail)
# Flat aliases still available
class AuthenticationError(BritecoreError):
pass
class NotFoundError(BritecoreError):
pass
class ValidationError(BritecoreError):
validation_errors: dict
Implementation Strategy
Enhance
BritecoreErrorbase class with status_code, error_code, request_id, raw_payloadUpdate
process_result()to extract and attach metadata to exceptionsExtract request_id from response headers (
X-Request-IDor similar)Parse server error payloads to extract structured error details
Preserve backwards compatibility - existing
str(exception)still worksDocument exception handling patterns in TROUBLESHOOTING.md
Acceptance Criteria
[ ] All exceptions have
status_code,error_code,request_idattributes[ ]
process_result()populates exception metadata from API responses[ ] Request ID extracted and attached to exceptions + logged
[ ] Validation errors available as
.validation_errorsdict[ ] Raw payload preserved for debugging
[ ] Backwards compatible -
str(exception)produces readable message
Phase 4: Transport Boundary & Middleware
Goal: Introduce pluggable transport/middleware hooks for retry, logging, tracing, custom headers.
Current State (legacy)
# Limited customization - stuck with built-in retry/rate limit logic
client = BritecoreAPIClient("site").init_client()
# No way to inject custom logging, tracing, headers without subclassing
v2.0.0 Target
# Rich middleware/hook system
from britecore_sdk.transport import Middleware, RequestContext, ResponseContext
class TracingMiddleware(Middleware):
def on_request(self, ctx: RequestContext) -> RequestContext:
"""Before request is sent."""
ctx.headers["X-Trace-ID"] = self.tracer.start_span()
return ctx
def on_response(self, ctx: ResponseContext) -> ResponseContext:
"""After response received."""
self.tracer.end_span(status=ctx.status_code)
return ctx
def on_error(self, error: Exception, ctx: RequestContext) -> Exception:
"""On request error."""
self.tracer.record_error(error)
return error
class CustomRetryMiddleware(Middleware):
def on_response(self, ctx: ResponseContext) -> ResponseContext:
if ctx.status_code == 429:
# Custom backoff logic
backoff = calculate_backoff(ctx.response_data)
raise RetryableError(backoff_seconds=backoff)
return ctx
client = BritecoreAPIClient("site").init_client(
middleware=[
TracingMiddleware(tracer=my_tracer),
CustomRetryMiddleware(),
]
)
# Or add middleware post-init
client.add_middleware(LoggingMiddleware(logger=my_logger))
Implementation Strategy
Define
Middlewarebase class with hooks:on_request,on_response,on_errorDefine
RequestContextandResponseContextto pass through middleware chainRefactor
do_request()to execute middleware chainProvide built-in middleware:
RetryMiddleware,LoggingMiddleware,RateLimitMiddlewareSupport middleware stack - order matters
Document middleware patterns with examples (OpenTelemetry, custom logging, etc.)
Acceptance Criteria
[ ]
Middlewarebase class defined with hook methods[ ]
RequestContextandResponseContexttypes defined[ ] Middleware chain execution in
do_request()[ ] Built-in middleware for retry, logging, rate limiting
[ ]
add_middleware()andremove_middleware()on client[ ] Examples: OpenTelemetry integration, custom logging, header injection
[ ] Documentation and tests for middleware system
Phase 5: Pagination Ergonomics
Goal: Add iterator helpers for list endpoints instead of manual page plumbing.
Current State (legacy)
# Manual pagination - error-prone
page = 1
all_quotes = []
while True:
response = list_quotes(page=page, limit=100, client=client)
all_quotes.extend(response["data"])
if len(response["data"]) < 100:
break
page += 1
v2.0.0 Target
# Iterator-based pagination - Pythonic
from britecore_sdk.api.api_calls.v2 import quotes
# Option 1: Iterator pattern
for quote in quotes.iter_quotes(limit=100, client=client):
print(f"Quote: {quote.quote_number}")
# Option 2: Collect all with auto-pagination
all_quotes = list(quotes.iter_quotes(client=client))
# Option 3: Async iterator
async for quote in quotes.aiter_quotes(client=client):
print(f"Quote: {quote.quote_number}")
Iterator Implementation
from typing import Iterator, AsyncIterator
from britecore_sdk.api.responses import QuoteResponse
def iter_quotes(
client: BritecoreAPIClient,
limit: int = 100,
**kwargs
) -> Iterator[QuoteResponse]:
"""Iterate over all quotes, handling pagination automatically."""
page = 1
while True:
response = list_quotes(page=page, limit=limit, client=client, **kwargs)
if not response.data:
break
for item in response.data:
yield QuoteResponse.from_api(item)
if len(response.data) < limit:
break
page += 1
async def aiter_quotes(
client: AsyncBritecoreAPIClient,
limit: int = 100,
**kwargs
) -> AsyncIterator[QuoteResponse]:
"""Async iterator for quotes with automatic pagination."""
page = 1
while True:
response = await alist_quotes(page=page, limit=limit, client=client, **kwargs)
if not response.data:
break
for item in response.data:
yield QuoteResponse.from_api(item)
if len(response.data) < limit:
break
page += 1
Implementation Strategy
Add
iter_*()function for each list endpointAdd
aiter_*()async function for each list endpointSupport
limitparameter for page sizeSupport filtering kwargs (pass through to underlying list function)
Handle
is_last_pageor similar field in API responsesDocument pagination patterns with examples
Acceptance Criteria
[ ] Iterator functions added for all list endpoints
[ ] Async iterator functions added for all list endpoints
[ ] Manual pagination still supported (backwards compatible)
[ ] Iterator handles empty results gracefully
[ ] Iterator supports filtering parameters
[ ] Examples document iterator usage patterns
Phase 6: Legacy Cleanup
Goal: Remove/deprecate v1-only or compatibility shims from core path; keep migration helpers in separate module.
Current State (legacy)
src/britecore_sdk/
├── classes/ # Legacy compatibility layer (deprecated)
├── api/api_calls/
│ ├── v1/ # Old versioned endpoints (still supported for backwards compat)
│ └── v2/ # New endpoints
└── ...
v2.0.0 Target
src/britecore_sdk/
├── api/api_calls/
│ ├── v2/ # Current active endpoints (all v2)
│ └── _compat/ # Migration helpers ONLY (moved from v1/)
├── models/ # Response models
├── validators/ # Input validators
├── transport/ # Pluggable transport/middleware
├── responses/ # Response envelopes
└── ...
# Removed or moved:
# - classes/ → Remove entirely, direct to models/validators
# - api_calls/v1/* → Move useful utilities to _compat/
# - Legacy compatibility shims
What Gets Removed
# REMOVED in v2.0.0:
from britecore_sdk.classes.quote import Quote # ❌ Use models instead
# REMOVED in v2.0.0:
from britecore_sdk.api.api_calls.v1.custom_ui import ... # ❌ Moved to compat helpers with migration guide
# STILL WORKS in v2.0.0:
from britecore_sdk.api.api_calls.v2.quotes import retrieve_quote # ✅
Migration Helpers Module
src/britecore_sdk/api/_compat/
├── __init__.py
├── v1_route_mapping.py # Maps old v1 imports to new locations
├── migration_guide.md # User-facing migration instructions
└── examples/
└── v1_to_v2_migration.py
Implementation Strategy
Audit
classes/module - move useful models tomodels/, remove restReview
api_calls/v1/- preserve supported wrappers when the upstream API still has nov2equivalentMove migration shims to
api/_compat/with clear deprecation noticesUpdate imports in
__init__.pyto point to new locationsRemove circular import workarounds and other v1-specific hacks
Create archived adoption notes in
docs/migrations/
Acceptance Criteria
[ ]
classes/module removed or fully deprecated[ ] Supported
api_calls/v1wrappers retained when nov2SDK equivalent exists[ ] Migration helpers available in
_compat/with clear instructions[ ] No circular imports or compatibility shims in core path
[ ]
__all__exports cleaned up[ ] Archived adoption notes provided for the major 2.0.0 design changes
Implementation Timeline
Week 1-2: Foundation
Phase 1: Client lifecycle parameter support
Phase 3: Enhanced exception model
Week 3-4: Type Safety
Phase 2: Response models and typed returns
Phase 5: Pagination iterators
Week 5-6: Extensibility
Phase 4: Transport middleware system
Phase 6: Legacy cleanup
Version Strategy
Historical note: This roadmap captured pre-release planning. The current 2.x policy does not treat all
api_calls/v1wrappers as legacy, and it does not require a blanket SDK-widev1→v2rewrite.
1.6.0 (Minor - Deprecations)
Add deprecation warnings for implicit client usage
Add new explicit client pattern alongside old one
Response models available but optional
Typed exceptions available but not default
New middleware system available for early adopters
1.7.0 (Minor - Foundation)
Pagination iterators available
Adoption/design notes published
Deprecations become more vocal
v2.0.0 (Major - Breaking)
Remove implicit client fallback
Only explicit client API available
Response models mandatory
Typed exceptions with metadata
Transport middleware required pattern
Legacy
classes/removedSupported
api_calls/v1wrappers retained where the upstream API or SDK coverage still requires them
Testing Strategy
Each phase should include:
Unit tests for new functionality
Integration tests with mock API
Backwards compatibility tests (where applicable)
Migration path tests (old code still works, with warnings)
Type checking tests (mypy, pyright)
Documentation Updates
For each phase:
Update CHANGELOG.md with changes
Update DEPRECATION.md if applicable
Add/update docstrings with examples
Create/update migration guide in
docs/migrations/Update README.md and GETTING_STARTED.md
Add examples in
examples/
Success Metrics
[ ] All phases completed
[ ] 100% type hint coverage (no
Anyin public API)[ ] Zero breaking changes in 1.x releases
[ ] Clear adoption guidance for explicit-client patterns and related 2.0.0 design changes
[ ] Cleaner, more maintainable codebase
[ ] Community feedback positive on v2 design
See Also
DEPRECATION.md — Deprecation policy
AGENTS.md — Development workflow
CONTRIBUTING.md — Maintainer guidelines