Problem
10 active ConfigurableResource classes independently implement the same requests.Session wrapper pattern, duplicating session lifecycle, URL construction, request wrapping, error handling, and auth setup. This makes it hard to add cross-cutting improvements (retries, rate limiting, metrics) and increases the cost of adding new API integrations.
Approach
Hook-based single-inheritance base class (BaseHTTPResource) in src/teamster/libraries/http/resources.py. Each subclass overrides only what it needs. The base provides built-in retry via tenacity, standardized error handling with rate-limit awareness, and pagination helpers for three common patterns.
Active resources (10)
| Resource |
Auth |
Pagination |
Tier |
| SmartRecruitersResource |
X-SmartToken header |
None |
1 |
| PowerSchoolEnrollmentResource |
Basic auth |
page |
1 |
| OvergradResource |
ApiKey header |
offset |
1 |
| KnowBe4Resource |
Bearer header |
page |
1 |
| ZendeskResource |
HTTPBasicAuth |
cursor |
2 |
| FinalsiteResource |
JWT bearer |
cursor |
2 |
| CoupaResource |
OAuth2Session |
offset |
2 |
| GrowResource |
OAuth2 token fetch |
offset |
2 |
| AdpWorkforceNowResource |
OAuth2Session + mTLS |
offset |
3 |
| DeansListResource |
API key per school |
offset |
3 |
Dead resources (4, preserved untouched)
AdpWorkforceManagerResource, MClassResource, DibelsDataSystemResource, CouchdropResource — no active consumers.
Base class design
Extension hooks
| Hook |
Default behavior |
Override example |
_setup_session() |
No-op (subclass sets auth + _base_url) |
Every subclass |
_prepare_request(method, url, kwargs) |
Pass-through |
DeansList injects school_id |
_handle_error(response, error) |
429: sleep + retry; 401: re-auth + retry; 5xx: retry; other: raise |
Zendesk custom rate-limit headers |
_get_retry_after(response) |
Parses Retry-After / X-RateLimit-Reset headers |
ADP WFN computed delay |
_reauthenticate() |
Re-raises (no re-auth) |
OAuth2 token refresh flows |
Built-in retry (tenacity)
stop_after_attempt(3)
wait_exponential_jitter(initial=1, max=60)
retry_if_exception_type(HTTPError)
Pagination helpers
All return Iterator[list[dict]] with fetch_page and extract_records callbacks.
_paginate_cursor — cursor-based (Zendesk, Finalsite)
_paginate_offset — offset/limit (Overgrad, Grow, Coupa, DeansList, ADP WFN)
_paginate_page — page number (KnowBe4, PowerSchool)
Migration tiers
Tier 1 — Direct drop-in (4 resources)
SmartRecruitersResource, PowerSchoolEnrollmentResource, OvergradResource, KnowBe4Resource
Override _setup_session() only, optionally _get_url().
Tier 2 — Additional hooks (4 resources)
ZendeskResource, FinalsiteResource, CoupaResource, GrowResource
Uses _get_retry_after override, OAuth2Session, or non-trivial _setup_session.
Tier 3 — Complex (2 resources)
AdpWorkforceNowResource, DeansListResource
OAuth2 + mTLS, _prepare_request override, custom Avro writing.
Testing
- Base class unit tests — mocked request pipeline, retry, error handling, pagination helpers
- Subclass mocked tests —
_setup_session, _get_url, override behavior per resource
- Pagination contract tests — multi-page sequences with realistic response shapes, edge cases
- Integration validation —
dagster definitions validate after each tier
Design spec
docs/superpowers/specs/2026-03-25-base-http-resource-design.md
Problem
10 active
ConfigurableResourceclasses independently implement the samerequests.Sessionwrapper pattern, duplicating session lifecycle, URL construction, request wrapping, error handling, and auth setup. This makes it hard to add cross-cutting improvements (retries, rate limiting, metrics) and increases the cost of adding new API integrations.Approach
Hook-based single-inheritance base class (
BaseHTTPResource) insrc/teamster/libraries/http/resources.py. Each subclass overrides only what it needs. The base provides built-in retry via tenacity, standardized error handling with rate-limit awareness, and pagination helpers for three common patterns.Active resources (10)
Dead resources (4, preserved untouched)
AdpWorkforceManagerResource, MClassResource, DibelsDataSystemResource, CouchdropResource — no active consumers.
Base class design
Extension hooks
_setup_session()_base_url)_prepare_request(method, url, kwargs)_handle_error(response, error)_get_retry_after(response)_reauthenticate()Built-in retry (tenacity)
stop_after_attempt(3)wait_exponential_jitter(initial=1, max=60)retry_if_exception_type(HTTPError)Pagination helpers
All return
Iterator[list[dict]]withfetch_pageandextract_recordscallbacks._paginate_cursor— cursor-based (Zendesk, Finalsite)_paginate_offset— offset/limit (Overgrad, Grow, Coupa, DeansList, ADP WFN)_paginate_page— page number (KnowBe4, PowerSchool)Migration tiers
Tier 1 — Direct drop-in (4 resources)
SmartRecruitersResource, PowerSchoolEnrollmentResource, OvergradResource, KnowBe4Resource
Override
_setup_session()only, optionally_get_url().Tier 2 — Additional hooks (4 resources)
ZendeskResource, FinalsiteResource, CoupaResource, GrowResource
Uses
_get_retry_afteroverride, OAuth2Session, or non-trivial_setup_session.Tier 3 — Complex (2 resources)
AdpWorkforceNowResource, DeansListResource
OAuth2 + mTLS,
_prepare_requestoverride, custom Avro writing.Testing
_setup_session,_get_url, override behavior per resourcedagster definitions validateafter each tierDesign spec
docs/superpowers/specs/2026-03-25-base-http-resource-design.md