feat: add template gallery read endpoints to TemplateClient - #603
Draft
scottlovegrove wants to merge 5 commits into
Draft
feat: add template gallery read endpoints to TemplateClient#603scottlovegrove wants to merge 5 commits into
scottlovegrove wants to merge 5 commits into
Conversation
Adds getTemplates, getTemplateCategories, and getTemplatesByIds to TemplateClient, exposing the Doist gallery, user templates, and workspace templates. These endpoints are live but undocumented in the public OpenAPI spec. Introduces a full Zod TemplateSchema + TemplateCategorySchema with runtime validation, derives query-filter unions from the base response unions to keep a single source of truth, and joins template IDs into a CSV for the GET /templates/get endpoint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
doistbot
reviewed
May 15, 2026
doistbot
left a comment
Member
There was a problem hiding this comment.
This PR introduces the template gallery read endpoints to the SDK alongside comprehensive Zod schemas for runtime validation. Exposing these features is a great addition that carefully navigates API quirks like query-filter unions and response map keys. A few refinements would help polish the implementation, particularly around enforcing input constraints for template IDs, strictly validating raw transport shapes before parsing, reusing existing constants and request utilities, and making the test fixtures and assertions a bit more robust.
- Validate templateIds in getTemplatesByIds (non-empty array, 1..100 IDs,
no empty strings) before building the CSV, throwing TodoistArgumentError.
- Validate that the /templates/get response actually contains a `templates`
object instead of silently falling back to `{}` on malformed payloads.
- Type all three new request<> calls with raw transport shapes
(RawGetTemplates*Response) so domain types only appear after validation,
matching the rest of the client.
- Drop locally-defined TEMPLATE_VIEW_TYPES; reuse PROJECT_VIEW_STYLES per
AGENTS.md single-source-of-truth rule.
- Use shared spreadIfDefined helper for optional locale/nextCursor.
- Hoist MOCK_TEMPLATE_API fixture to module scope so getTemplates and
getTemplatesByIds tests share one source of truth.
- Assert template_ids via URL.searchParams instead of hard-coding the
%2C-encoded form.
- Add unit tests covering each input-validation rejection and the
malformed-response error path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…knowns - Define GetTemplatesResponseSchema, GetTemplateCategoriesResponseSchema, and GetTemplatesByIdsResponseSchema in types/templates/types.ts, mirroring the server-side TypedDicts in todoist/apps/import_export. - Derive GetTemplates*Response types via z.infer so the public TS types and the runtime validators stay in lockstep. - GetTemplatesByIdsResponseSchema uses .transform() to rebuild the templates map keyed by each validated template's own `id`, sidestepping the HTTP client's snake_case → camelCase key mangling at the schema level instead of in the client. - Drop the locally-defined RawGetTemplates*Response shapes and unknown fallbacks in TemplateClient; request<> is now typed with the published domain types like every other client, and the response is parsed through the new validators. - Add validateGetTemplatesResponse / validateGetTemplateCategoriesResponse / validateGetTemplatesByIdsResponse via createValidator. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 tasks
User templates omit `import_url` entirely from the response (see
map_user_template_to_contentful_response in todoist/apps/import_export/
controllers/common.py), so the schema needs to accept undefined as well
as null. Surfaced by a live `getTemplates({ templateSource: 'user' })`
call, which was failing with "expected string, received undefined".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's `npx @arethetypeswrong/cli` resolved attw 0.18.2 fresh each run, which in turn pulled the latest transitive fflate. fflate 0.8.3 (published 2026-05-16) broke attw's tarball parsing with "Cannot read properties of undefined (reading 'filename')". Local checks were still passing because they had cached fflate 0.8.2. - Install @arethetypeswrong/cli as a devDependency so it resolves through package-lock.json instead of the live registry, and call it as `attw` rather than via `npx`. - Add an `overrides` entry forcing fflate@0.8.2 so attw can read the packed tarball again. Remove once attw / fflate ship a fix. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
scottlovegrove
marked this pull request as draft
May 22, 2026 19:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
getTemplates,getTemplateCategories, andgetTemplatesByIdsto the SDK, exposing the Todoist template gallery (Doist, user, and workspace templates). These endpoints are live but absent from the public OpenAPI spec.TemplateSchema+TemplateCategorySchemawith runtime validation.TEMPLATE_TYPE_FILTERS,TEMPLATE_SOURCE_FILTERS) from base response unions to keep a single source of truth — adding'all'/'workspace'only as accepted query inputs while keeping the response schema strict.templateIdsinto a CSV (the API expects a comma-separated string param) and rebuilds the response map keyed by each template's ownidso the auto camelCase conversion can't mangle the keys.PR 1 of 2 — write endpoints (user-template CRUD + multipart upload) will follow in a separate PR.
Test plan
npm run check(oxlint + oxfmt) passesnpm test— full suite, 589 tests pass/getID-map quirk🤖 Generated with Claude Code