Parent: #297
Depends on: #298
Goal
Identify response parsing and model-construction logic currently embedded in synchronous Mlb endpoint methods that should be shared with the async client.
The objective is to avoid maintaining two independent copies of endpoint parsing without rewriting the existing synchronous API.
Scope
- Audit representative
Mlb methods for transport/parsing coupling
- Identify minimal shared helpers that can be reused by
Mlb and AsyncMlb
- Extract only logic needed to support the initial async vertical slice
- Preserve existing return types and endpoint-specific empty-result behavior
- Keep public method signatures unchanged
Parser package architecture
Create a private, transport-independent parser package under mlbstatsapi:
mlbstatsapi/
├── _parsers/
│ ├── __init__.py
│ ├── teams.py
│ ├── people.py
│ └── schedules.py
The leading underscore marks _parsers as an internal implementation package rather than part of the stable public API.
Organize parsers by domain rather than by individual endpoint. For example, teams.py can eventually contain related team response parsers such as parse_team, parse_teams, roster parsing, and coach parsing as async endpoint coverage expands.
For the initial vertical slice, implement only the parsing/model-construction helpers needed by:
get_team
get_person
get_schedule
The parser package is expected to grow over time as more Mlb endpoints gain async equivalents, so use a package from the beginning rather than a single _parsers.py module.
Responsibility boundary
The parser layer should own only transport-independent response interpretation and model construction.
Mlb / AsyncMlb
endpoint arguments and endpoint semantics
↓
MlbDataAdapter / AsyncMlbDataAdapter
HTTP, status handling, retries, timeouts, JSON decoding
↓
_parsers
decoded response data -> existing Pydantic/domain models
↓
models
domain object definitions
Keep request construction and endpoint argument validation in Mlb / AsyncMlb.
Keep HTTP status handling, retries, timeouts, cancellation, JSON decoding, and client ownership in the adapters.
Do not make models responsible for understanding endpoint response envelopes such as data["teams"] or data["people"].
Contract requirements from #298
Shared parsing/model code must preserve the behavioral contract defined in #298:
- Equivalent sync and async endpoint responses produce the same existing Pydantic/domain model types
- Existing
None, [], and {} endpoint behavior remains unchanged
- Endpoint-specific 404 interpretation remains a public endpoint concern and must not be accidentally changed by parsing extraction
- JSON-decoded data should enter the same parsing/model-construction path wherever practical
- Parsing/model failures are not transport failures and must not be retried by shared parsing code
- Shared helpers must remain transport-independent and must not depend on
requests or the selected async HTTP library
- Do not introduce shared mutable per-request parsing state that could allow concurrent async operations to interfere with one another
Initial parser direction
Prefer small, domain-specific pure functions rather than prematurely introducing a generic parser abstraction.
Conceptually:
parse_team(data) -> Team | None
parse_person(data) -> Person | None
parse_schedule(data) -> Schedule | None
The implementation should preserve existing synchronous behavior first. Once the sync path uses the shared helpers and remains green, the async client can reuse the same parsing functions.
Do not generalize functions such as parse_first_model(data, key, model) until repeated implementations demonstrate a real common abstraction.
Constraints
- No broad rewrite of
mlb_api.py
- No behavior change to existing synchronous methods
- No new public API unless explicitly justified
- Favor small pure parsing/model-construction helpers
- Do not move HTTP status, retry, timeout, cancellation, or client-lifecycle policy into parsing helpers
- Do not make
_parsers depend on synchronous or asynchronous transport libraries
- Keep
_parsers private; do not re-export parser helpers from the package root
Acceptance criteria
Refs #297
Contract: #298
Parent: #297
Depends on: #298
Goal
Identify response parsing and model-construction logic currently embedded in synchronous
Mlbendpoint methods that should be shared with the async client.The objective is to avoid maintaining two independent copies of endpoint parsing without rewriting the existing synchronous API.
Scope
Mlbmethods for transport/parsing couplingMlbandAsyncMlbParser package architecture
Create a private, transport-independent parser package under
mlbstatsapi:The leading underscore marks
_parsersas an internal implementation package rather than part of the stable public API.Organize parsers by domain rather than by individual endpoint. For example,
teams.pycan eventually contain related team response parsers such asparse_team,parse_teams, roster parsing, and coach parsing as async endpoint coverage expands.For the initial vertical slice, implement only the parsing/model-construction helpers needed by:
get_teamget_personget_scheduleThe parser package is expected to grow over time as more
Mlbendpoints gain async equivalents, so use a package from the beginning rather than a single_parsers.pymodule.Responsibility boundary
The parser layer should own only transport-independent response interpretation and model construction.
Keep request construction and endpoint argument validation in
Mlb/AsyncMlb.Keep HTTP status handling, retries, timeouts, cancellation, JSON decoding, and client ownership in the adapters.
Do not make models responsible for understanding endpoint response envelopes such as
data["teams"]ordata["people"].Contract requirements from #298
Shared parsing/model code must preserve the behavioral contract defined in #298:
None,[], and{}endpoint behavior remains unchangedrequestsor the selected async HTTP libraryInitial parser direction
Prefer small, domain-specific pure functions rather than prematurely introducing a generic parser abstraction.
Conceptually:
The implementation should preserve existing synchronous behavior first. Once the sync path uses the shared helpers and remains green, the async client can reuse the same parsing functions.
Do not generalize functions such as
parse_first_model(data, key, model)until repeated implementations demonstrate a real common abstraction.Constraints
mlb_api.py_parsersdepend on synchronous or asynchronous transport libraries_parsersprivate; do not re-export parser helpers from the package rootAcceptance criteria
_parsers/package created with domain-oriented modules for the initial vertical sliceMlbcallersget_team,get_person, andget_scheduleRefs #297
Contract: #298