Skip to content

Commit 7fd4a44

Browse files
committed
docs: update CLAUDE.md for post-fragment-refactoring state
- Update Shared Fragments table with all queries now using fragments - Add key fields: isFavorite, popularity, bio, fansCount, label, copyright - Document partial error handling in get_data() - Document __typename injection for single-member unions - Add connection pooling usage example
1 parent bbba089 commit 7fd4a44

1 file changed

Lines changed: 30 additions & 8 deletions

File tree

CLAUDE.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,17 @@ pipe.deezer.com/api → schema.json → schema.graphql → deezer_py
174174

175175
`queries/fragments.graphql` defines reusable field sets shared across multiple queries:
176176

177-
| Fragment | Used by | Key fields |
178-
| ---------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------- |
179-
| `TrackFields` | flow, flow_config_tracks, smart_tracklist, charts, user_charts, fav_tracks | id, title, ISRC, diskInfo, duration, isExplicit, album, contributors |
180-
| `ArtistFields` | charts, user_charts, recommendations, fav_artists | id, name, picture, fansCount |
181-
| `AlbumFields` | charts, user_charts, recommendations, fav_albums | id, displayTitle, type, cover, contributors, releaseDate |
182-
| `PlaylistFields` | charts, recommendations, fav_playlists | id, title, picture, estimatedTracksCount, owner |
183-
| `PageInfoFields` | All paginated queries | hasNextPage, endCursor |
177+
| Fragment | Used by | Key fields |
178+
| ---------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
179+
| `TrackFields` | search, get_track, get_album, get_artist, get_playlist, flow, flow_config_tracks, smart_tracklist, charts, user_charts, fav_tracks | id, title, ISRC, diskInfo, duration, isExplicit, isFavorite, popularity, album, contributors |
180+
| `ArtistFields` | search, get_artist, charts, user_charts, recommendations, fav_artists, recently_played | id, name, picture, fansCount, isFavorite, bio (summary + full) |
181+
| `AlbumFields` | search, get_album, get_artist, charts, user_charts, recommendations, fav_albums, recently_played | id, displayTitle, type, cover, contributors, releaseDate, isExplicit, isFavorite, fansCount, label, copyright |
182+
| `PlaylistFields` | search, get_playlist, charts, recommendations, fav_playlists, recently_played | id, title, picture, estimatedTracksCount, fansCount, isFavorite, description, owner |
183+
| `PageInfoFields` | All paginated queries | hasNextPage, endCursor |
184184

185-
ariadne-codegen generates `fragments.py` with Pydantic base classes (`TrackFields`, `ArtistFields`, etc.). Query model classes inherit from these via multiple inheritance, e.g., `GetChartsChartsCountryTracksEdgesNode(TrackFields)`. This means fragment fields are type-safe and IDE-discoverable on all inheriting models.
185+
**All entity queries use shared fragments.** Every query that returns tracks, albums, artists, or playlists uses the corresponding fragment via `...TrackFields` etc. Some queries (e.g., `get_track.graphql`, `get_album.graphql`) extend the fragment with additional fields like `media`, `lyrics`, `url`, or `tracksCount`.
186+
187+
ariadne-codegen generates `fragments.py` with Pydantic base classes (`TrackFields`, `ArtistFields`, etc.). Query model classes inherit from these via multiple inheritance, e.g., `GetChartsChartsCountryTracksEdgesNode(TrackFields)`. This means fragment fields are type-safe and IDE-discoverable on all inheriting models. Consumers can type method parameters as `TrackFields` and accept any query-specific track model.
186188

187189
To use a fragment in a new query, reference it with `...TrackFields` in the `.graphql` file.
188190

@@ -216,6 +218,26 @@ ARL cookie → POST auth.deezer.com/login/arl?jo=p&rto=c&i=c → JWT (6 min TTL)
216218
- JWT expiration is decoded from the token payload (base64url-encoded second segment)
217219
- Auto-refresh triggers 30 seconds before expiry
218220

221+
### Response Handling
222+
223+
The `DeezerBaseClient.get_data()` method handles two important edge cases:
224+
225+
1. **Partial errors**: When the GraphQL response contains both `data` and `errors` (e.g., deleted albums in a favorites list), the errors are logged but valid data is returned. Only responses with errors and no data raise `GraphQLClientGraphQLMultiError`.
226+
227+
2. **Missing `__typename` injection**: The Deezer API omits `__typename` for single-member union types (e.g., `Contributor` is always `Artist`). Since Pydantic discriminated unions require this field, `_inject_missing_typenames()` recursively patches it into the response before model validation. The mapping is defined in `_TYPENAME_PATCHES`.
228+
229+
### Connection Pooling
230+
231+
For production use, pass an `httpx.AsyncClient` to avoid creating a new connection for every request:
232+
233+
```python
234+
async with httpx.AsyncClient() as http:
235+
client = DeezerGQLClient(arl="your_arl", http_client=http)
236+
# All requests reuse the same connection pool
237+
```
238+
239+
If no `http_client` is provided, the base client creates (and closes) a throwaway `httpx.AsyncClient` per request. This works but is inefficient for high-volume usage like library syncs.
240+
219241
## Key Configuration
220242

221243
- **Python**: 3.12+ required (tested on 3.12, 3.13)

0 commit comments

Comments
 (0)