feat(api): add GET /content/schema/{post,collection,author} endpoints - #180
Conversation
Exposes the sync worker's TypeBox frontmatter schemas directly so downstream consumers have a single source of truth for valid post, collection, and author frontmatter shape.
|
Warning Review limit reached
Next review available in: 45 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughThree new content schema routes are added for post, collection, and author frontmatter, all built through a shared route factory. The app registers the new routes, and each endpoint has a corresponding test. ChangesContent Schema Routes
Estimated code review effort: 2 (Simple) | ~10 minutes Sequence Diagram(s)sequenceDiagram
participant createApp
participant createSchemaRoute
participant Fastify
participant Client
createApp->>Fastify: register schema route plugins
createSchemaRoute->>Fastify: define GET /content/schema/*
Client->>Fastify: GET request
Fastify-->>Client: 200 JSON schema response
Related PRs: None. Suggested labels: api, enhancement Suggested reviewers: None. Poem: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
apps/api/src/routes/content/schema-post.ts (2)
5-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStashing the real schema in
examplesis semantically off.
examplesis meant to hold sample response instances, not the schema definition itself. Consumers/tools generating OpenAPI docs or client SDKs fromexamplesmay render the schema object as if it were example data, which is confusing. If avoiding Fastify's response validation is the real goal, consider a dedicated OpenAPI vendor extension (e.g.x-schema) instead of repurposingexamples.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/src/routes/content/schema-post.ts` around lines 5 - 12, The SchemaPostResponseSchema definition is using examples to store the schema itself, which is the wrong semantic for response examples. Update the SchemaPostResponseSchema in schema-post.ts so the real schema is not placed in examples; instead, use a dedicated OpenAPI vendor extension like x-schema or another non-example metadata field while keeping the response shape and description intact.
5-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate this route-registration boilerplate across all three schema route files.
schema-post.ts,schema-collection.ts, andschema-author.tsare structurally identical apart from path, description, and schema reference. Consider extracting a small factory, e.g.createSchemaRoute(path, description, schema), to avoid triplicated logic and keep future changes (e.g., adjusting the response-schema workaround) in one place.♻️ Example factory approach
// apps/api/src/routes/content/createSchemaRoute.ts import type { FastifyPluginAsync } from "fastify"; import { Type, type TSchema } from "typebox"; export function createSchemaRoute( path: string, description: string, schema: TSchema, ): FastifyPluginAsync { const ResponseSchema = Type.Object( {}, { additionalProperties: true, description, examples: [schema] }, ); return async (fastify) => { fastify.get( path, { schema: { description, response: { description: "Successful", content: { "application/json": { schema: ResponseSchema } }, }, }, }, }, async (_request, reply) => { reply.code(200); reply.send(schema); }, ); }; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/api/src/routes/content/schema-post.ts` around lines 5 - 38, The three schema route files duplicate the same Fastify route-registration logic, so extract a shared factory like createSchemaRoute and use it from schema-post, schema-collection, and schema-author. Move the common fastify.get setup, response-schema workaround, and reply.send behavior into the factory, parameterized by path, description, and the schema reference (e.g. PostMetaSchema/CollectionMetaSchema/AuthorMetaSchema), so future changes only happen in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@apps/api/src/routes/content/schema-post.ts`:
- Around line 5-12: The SchemaPostResponseSchema definition is using examples to
store the schema itself, which is the wrong semantic for response examples.
Update the SchemaPostResponseSchema in schema-post.ts so the real schema is not
placed in examples; instead, use a dedicated OpenAPI vendor extension like
x-schema or another non-example metadata field while keeping the response shape
and description intact.
- Around line 5-38: The three schema route files duplicate the same Fastify
route-registration logic, so extract a shared factory like createSchemaRoute and
use it from schema-post, schema-collection, and schema-author. Move the common
fastify.get setup, response-schema workaround, and reply.send behavior into the
factory, parameterized by path, description, and the schema reference (e.g.
PostMetaSchema/CollectionMetaSchema/AuthorMetaSchema), so future changes only
happen in one place.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f2f16cea-4877-4b83-ad4b-7b4e7b52e628
📒 Files selected for processing (7)
apps/api/src/createApp.tsapps/api/src/routes/content/schema-author.test.tsapps/api/src/routes/content/schema-author.tsapps/api/src/routes/content/schema-collection.test.tsapps/api/src/routes/content/schema-collection.tsapps/api/src/routes/content/schema-post.test.tsapps/api/src/routes/content/schema-post.ts
Addresses CodeRabbit's suggestion on PR playfulprogramming#180 to de-duplicate the identical route/response-wrapper boilerplate across schema-post.ts, schema-collection.ts, and schema-author.ts.
| @@ -0,0 +1,10 @@ | |||
| import { AuthorMetaSchema } from "../../../../worker/src/tasks/sync-author/types.ts"; | |||
There was a problem hiding this comment.
Let's avoid importing files from outside the current package like this. I'd move these schemas to packages/common (will need to add the typebox dependency) and import them through @playfulprogramming/common instead of referencing the file path.
PostMetaSchema, CollectionMetaSchema, and AuthorMetaSchema move from apps/worker's per-task types.ts files into packages/common, resolving the cross-app import flagged in the PR description (apps/api was reaching into apps/worker via a relative path). typebox is already a packages/common dependency via the catalog, so no manifest change is needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
GET /content/schema/post,GET /content/schema/collection,GET /content/schema/author— each returning the corresponding TypeBox frontmatter schema (PostMetaSchema,CollectionMetaSchema,AuthorMetaSchema) directly as the response body.schema-post.ts,schema-collection.ts,schema-author.ts), following the existingprofiles.tspattern and the project's one-route-per-file convention.createApp.tsalongside the existing content routes.These three schemas are exposed as-is with no transformation — downstream consumers should treat them as the source of truth for frontmatter shape, since they're the exact schemas the sync worker validates against.
Implementation note
Each route's
response[200]schema is a permissive object (additionalProperties: true) with the realMetaSchemaattached viaexamples, rather than using theMetaSchemaitself as the response schema. Using the frontmatter schema directly as the Fastify response schema causes a 500 (fast-json-stringifytreats it as the shape of post/collection/author data, not a JSON Schema document, and complains about missing required fields liketitle). The permissive-wrapper approach keeps runtime serialization working and still surfaces the real schema shape in the generated OpenAPI docs.Design question for James
These three route files import
PostMetaSchema/CollectionMetaSchema/AuthorMetaSchemadirectly fromapps/worker/src/tasks/*/types.tsvia a relative path, since that's where the schemas already live. This is the first cross-app import in the codebase — elsewhere, sharing goes throughpackages/*, with apps depending on packages rather than on each other directly. Flagging in case you'd rather these schemas move intopackages/common(or a new small package) as a follow-up; Docker builds both apps from the same checkout today, but that's not a guarantee this pattern should rely on long-term.Test plan
pnpm test:unitpasses (lint, knip, publint, sherif, vitest across all NX projects)pnpm prettier --check .passes on all changed files/openapi.jsonto confirm the response is documented sensibly (permissive schema + concrete example) rather than misleadingly requiring frontmatter fields on the response itselfSummary by CodeRabbit
New Features
/content/schema/*.Tests