fix: harden research API response schemas and add error responses#132
fix: harden research API response schemas and add error responses#132sweetmantech merged 1 commit intomainfrom
Conversation
Supersedes closed PR #101, which modified the old monolithic api-reference/openapi.json before the spec was split into per-domain files. This ports the same changes onto api-reference/openapi/research.json. - Add reusable ResearchErrorResponse component ({ status: "error", error }) - Add 400 and 401 error responses to all 30 /api/research/* endpoints - Add example: "success" to every response schema status field with the success/error enum - Tighten /api/research/charts query params (country ISO-2 pattern, interval/type enums with defaults, latest as boolean) - Strengthen /api/research/enrich request schema (require type=object and properties) Schema fixes (field name/type mismatches vs. actual handlers): | Schema | Change | Reason | |---------------------------------|-----------------------------------------------------|----------------------------------------------------| | ResearchCareerResponse | data -> career | Handler returns { career: data } | | ResearchWebResponse items | content -> snippet; added date, last_updated | Perplexity returns snippet | | ResearchEnrichResponse | Flattened research_basis.citations -> citations | Handler returns { output, citations } flat | | ResearchPeopleResult | Added id, publishedDate, author | Exa search returns these fields | Also restructures ResearchAudienceResponse, ResearchInstagramPostsResponse, and ResearchLookupResponse to match actual handler output (ported verbatim from PR #101).
📝 WalkthroughWalkthroughThe OpenAPI specification for the research API has been updated with new error response definitions (400/401 status codes), refined query parameter declarations with defaults and validation constraints, and restructured response/request schemas featuring field renames, new required properties, and redefined data shapes across multiple endpoints. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
api-reference/openapi/research.json (2)
3903-3957:⚠️ Potential issue | 🟡 MinorBreaking change:
postsrenamed totop_posts, newtop_reelsadded.Field renamed from
poststotop_postsand newtop_reelsarray added to better reflect the Chartmetric DeepSocial data structure. Clients expecting thepostsfield will need to update.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@api-reference/openapi/research.json` around lines 3903 - 3957, Update the API schema to reflect the breaking change: rename the old posts field to top_posts and add the new top_reels array in the ResearchInstagramPostsResponse schema; specifically, replace any references to "posts" with "top_posts" and ensure the ResearchInstagramPostsResponse properties include both "top_posts" and "top_reels" with the same item shape (url, likes, comments, timestamp) and additionalProperties allowed, and update any docs/tests that reference ResearchInstagramPostsResponse.posts to use ResearchInstagramPostsResponse.top_posts (and use top_reels where applicable).
3444-3461:⚠️ Potential issue | 🟡 MinorBreaking change:
career_stagerenamed tocareer.This renames the response field from
career_stagetocareerbased on the actual API handler output. Clients expecting the old field name will need to update their integrations.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@api-reference/openapi/research.json` around lines 3444 - 3461, The OpenAPI schema defines ResearchCareerResponse with a property named "career" but the change note says the field was renamed from "career_stage"; update any remaining schema, examples, and references that still use "career_stage" to use "career" consistently (or add a backward-compatible "career_stage" alias if you must preserve compatibility); specifically search and update references to ResearchCareerResponse and any examples or components that mention "career_stage" so they match the actual API handler output "career".
🧹 Nitpick comments (1)
api-reference/openapi/research.json (1)
3397-3400: Status field missingenumconstraint.Unlike other response schemas (e.g.,
ResearchAlbumsResponse),ResearchAudienceResponse.statuslacks theenum: ["success", "error"]constraint. This inconsistency could affect client-side validation.♻️ Suggested fix
"status": { "type": "string", + "enum": ["success", "error"], "example": "success" },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@api-reference/openapi/research.json` around lines 3397 - 3400, The status field in ResearchAudienceResponse (the property named status) is missing the enum constraint; update the schema for ResearchAudienceResponse.status to include enum: ["success", "error"] so it matches other response schemas and enables consistent client-side validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@api-reference/openapi/research.json`:
- Around line 3958-3987: The OpenAPI schema for ResearchLookupResponse was
changed so cross-platform IDs are nested under the "data" object
(ResearchLookupResponse -> properties -> data) instead of being top-level
properties; update any server/client code or docs that read top-level fields to
instead read ResearchLookupResponse.data.id,
ResearchLookupResponse.data.spotify_id,
ResearchLookupResponse.data.apple_music_id, and
ResearchLookupResponse.data.deezer_id, and ensure JSON serializers/deserializers
and type definitions (models/DTOs) reflect the nested "data" object with
additionalProperties allowed.
- Around line 4586-4599: The OpenAPI schema was changed: the response field
previously named "content" has been renamed to "snippet" and two new nullable
fields "date" and "last_updated" were added; update all usages and examples to
reference "snippet" (not "content"), add the new "date" and "last_updated"
properties to any model definitions and response examples, and update any
serialization/deserialization logic or client mappings that expect "content"
(search result models, e.g., the search result type) so they read/write
"snippet" and handle nullable "date" and "last_updated" values appropriately.
- Around line 3654-3673: The OpenAPI change made ResearchEnrichRequest.schema
require explicit "type" and "properties", which breaks existing clients; revert
this breaking change by making the schema permissive again: update
ResearchEnrichRequest.schema to accept either the new strict form or the
previous unconstrained object (e.g., replace the strict
required=["type","properties"] model with a oneOf that includes both the strict
object (with "type":"object" + "properties") and a generic object schema
allowing additionalProperties), and add/update the endpoint description to note
the preferred new strict schema and a deprecation/compatibility note for the
older form.
---
Outside diff comments:
In `@api-reference/openapi/research.json`:
- Around line 3903-3957: Update the API schema to reflect the breaking change:
rename the old posts field to top_posts and add the new top_reels array in the
ResearchInstagramPostsResponse schema; specifically, replace any references to
"posts" with "top_posts" and ensure the ResearchInstagramPostsResponse
properties include both "top_posts" and "top_reels" with the same item shape
(url, likes, comments, timestamp) and additionalProperties allowed, and update
any docs/tests that reference ResearchInstagramPostsResponse.posts to use
ResearchInstagramPostsResponse.top_posts (and use top_reels where applicable).
- Around line 3444-3461: The OpenAPI schema defines ResearchCareerResponse with
a property named "career" but the change note says the field was renamed from
"career_stage"; update any remaining schema, examples, and references that still
use "career_stage" to use "career" consistently (or add a backward-compatible
"career_stage" alias if you must preserve compatibility); specifically search
and update references to ResearchCareerResponse and any examples or components
that mention "career_stage" so they match the actual API handler output
"career".
---
Nitpick comments:
In `@api-reference/openapi/research.json`:
- Around line 3397-3400: The status field in ResearchAudienceResponse (the
property named status) is missing the enum constraint; update the schema for
ResearchAudienceResponse.status to include enum: ["success", "error"] so it
matches other response schemas and enables consistent client-side validation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: be144923-67e2-4d6f-8b2e-7c41f8ca78ea
📒 Files selected for processing (1)
api-reference/openapi/research.json
| "description": "JSON schema defining the fields to extract. Must include `\"type\": \"object\"` at the top level.", | ||
| "additionalProperties": true, | ||
| "properties": { | ||
| "type": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "object" | ||
| ], | ||
| "description": "Must be \"object\"" | ||
| }, | ||
| "properties": { | ||
| "type": "object", | ||
| "description": "Field definitions to extract", | ||
| "additionalProperties": true | ||
| } | ||
| }, | ||
| "required": [ | ||
| "type", | ||
| "properties" | ||
| ] |
There was a problem hiding this comment.
Breaking change: schema now requires explicit type and properties fields.
The ResearchEnrichRequest.schema now enforces that requests must include "type": "object" and "properties" at the top level. While the endpoint description at line 1391 documents this requirement, existing clients that relied on the previously unconstrained schema object will receive 400 errors.
Consider whether this warrants a deprecation period or if the prior behavior was already rejecting such requests server-side.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi/research.json` around lines 3654 - 3673, The OpenAPI
change made ResearchEnrichRequest.schema require explicit "type" and
"properties", which breaks existing clients; revert this breaking change by
making the schema permissive again: update ResearchEnrichRequest.schema to
accept either the new strict form or the previous unconstrained object (e.g.,
replace the strict required=["type","properties"] model with a oneOf that
includes both the strict object (with "type":"object" + "properties") and a
generic object schema allowing additionalProperties), and add/update the
endpoint description to note the preferred new strict schema and a
deprecation/compatibility note for the older form.
| "ResearchLookupResponse": { | ||
| "type": "object", | ||
| "description": "Artist profile resolved from a platform URL or ID.", | ||
| "description": "Artist profile resolved from a platform URL or ID. Cross-platform IDs are nested inside a `data` object.", | ||
| "properties": { | ||
| "status": { | ||
| "type": "string" | ||
| }, | ||
| "id": { | ||
| "type": "integer", | ||
| "description": "Chartmetric artist ID" | ||
| }, | ||
| "spotify_id": { | ||
| "type": "string" | ||
| }, | ||
| "apple_music_id": { | ||
| "type": "string" | ||
| "type": "string", | ||
| "example": "success" | ||
| }, | ||
| "deezer_id": { | ||
| "type": "string" | ||
| "data": { | ||
| "type": "object", | ||
| "description": "Cross-platform artist identifiers returned by Chartmetric.", | ||
| "properties": { | ||
| "id": { | ||
| "type": "integer", | ||
| "description": "Chartmetric artist ID" | ||
| }, | ||
| "spotify_id": { | ||
| "type": "string" | ||
| }, | ||
| "apple_music_id": { | ||
| "type": "string" | ||
| }, | ||
| "deezer_id": { | ||
| "type": "string" | ||
| } | ||
| }, | ||
| "additionalProperties": true | ||
| } | ||
| }, | ||
| "additionalProperties": true | ||
| } | ||
| }, |
There was a problem hiding this comment.
Breaking change: Cross-platform IDs moved into nested data object.
The response structure changed from top-level ID fields to a nested data object containing id, spotify_id, apple_music_id, and deezer_id. Clients directly accessing these fields at the response root will need updates.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi/research.json` around lines 3958 - 3987, The OpenAPI
schema for ResearchLookupResponse was changed so cross-platform IDs are nested
under the "data" object (ResearchLookupResponse -> properties -> data) instead
of being top-level properties; update any server/client code or docs that read
top-level fields to instead read ResearchLookupResponse.data.id,
ResearchLookupResponse.data.spotify_id,
ResearchLookupResponse.data.apple_music_id, and
ResearchLookupResponse.data.deezer_id, and ensure JSON serializers/deserializers
and type definitions (models/DTOs) reflect the nested "data" object with
additionalProperties allowed.
| "snippet": { | ||
| "type": "string", | ||
| "description": "Content snippet from the search result." | ||
| }, | ||
| "date": { | ||
| "type": "string", | ||
| "nullable": true, | ||
| "description": "Publication date if available." | ||
| }, | ||
| "last_updated": { | ||
| "type": "string", | ||
| "nullable": true, | ||
| "description": "Last updated date if available." | ||
| } |
There was a problem hiding this comment.
Breaking change: content renamed to snippet, new date fields added.
The content field is renamed to snippet for clarity. The new date and last_updated nullable fields are useful additions for temporal context in search results.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@api-reference/openapi/research.json` around lines 4586 - 4599, The OpenAPI
schema was changed: the response field previously named "content" has been
renamed to "snippet" and two new nullable fields "date" and "last_updated" were
added; update all usages and examples to reference "snippet" (not "content"),
add the new "date" and "last_updated" properties to any model definitions and
response examples, and update any serialization/deserialization logic or client
mappings that expect "content" (search result models, e.g., the search result
type) so they read/write "snippet" and handle nullable "date" and "last_updated"
values appropriately.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="api-reference/openapi/research.json">
<violation number="1" location="api-reference/openapi/research.json:2953">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**
The `enum: ["success", "error"]` constraint is silently removed from `ResearchEnrichResponse.status` (and identically from `ResearchWebResponse.status`), replaced with only `example: "success"`. The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| ], | ||
| "description": "Status of the request" | ||
| "description": "Status of the request", | ||
| "example": "success" |
There was a problem hiding this comment.
P1: Custom agent: Flag AI Slop and Fabricated Changes
The enum: ["success", "error"] constraint is silently removed from ResearchEnrichResponse.status (and identically from ResearchWebResponse.status), replaced with only example: "success". The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At api-reference/openapi/research.json, line 2953:
<comment>The `enum: ["success", "error"]` constraint is silently removed from `ResearchEnrichResponse.status` (and identically from `ResearchWebResponse.status`), replaced with only `example: "success"`. The PR description and test plan explicitly claim all 20 enum-bearing status fields retain their enum — that claim is false for these two schemas. This weakens schema validation: clients and code generators will no longer constrain the status field to known values. Restore the enum alongside the example to match every other research response schema in this file.</comment>
<file context>
@@ -2335,7 +2949,8 @@
],
- "description": "Status of the request"
+ "description": "Status of the request",
+ "example": "success"
},
"source_chat_id": {
</file context>
Combine the design/narrative overhaul (new 8-tab IA, deprecation notices, rebuilt Agent Onboarding, achromatic design system) with all API doc updates shipped to main since the branch diverged: - 8 research PRs (#132-#140): schema hardening, /research/track id-proxy, /research/curator Chartmetric contract, /research/track/playlists, error responses aligned with handler enforcement - Artist surface rename: /api/artist/socials -> /api/artists/{id}/socials - New endpoints: artists/pin, artists/unpin, admins/agent-signups - Removed dead surfaces: artist/segments, chat/segment, segment/fans - Caption length default -> none Conflict resolutions: - docs.json: kept design IA (Overview/Chat/Research/Artists/Catalog/Content/ Automation/Accounts), spliced in all new endpoints from main, removed stale nav refs to deleted surfaces - index.mdx, quickstart.mdx: kept design copy (richer, superseded main's verbose endpoint listing with card-based IA) - openapi/content.json: auto-merge preserved design's deprecation of /api/content/create alongside main's untouched body research.json, accounts.json, releases.json are byte-identical to main. 131 API mdx files / 131 nav entries / 0 orphans / 0 broken intra-doc links. Made-with: Cursor
Summary
Ports the changes from closed PR #101 onto the split OpenAPI spec. The original PR modified
api-reference/openapi.json(the old monolithic file), which has since been deleted onmainand split into per-domain files underapi-reference/openapi/. All research-related changes are re-applied here toapi-reference/openapi/research.json.This replaces closed PR #101.
ResearchErrorResponsecomponent ({ status: "error", error: "message" })400and401error responses to all 30/api/research/*endpoints via$refexample: "success"to all response schemastatusfields for consistency/api/research/chartsquery parameter constraints (country ISO-2 pattern,interval/typeenums,latestas boolean)/api/research/enrichrequestschemavalidation (must includetype: "object"andproperties)Schema fixes (from #101)
ResearchCareerResponsedata→career{ career: data }, not{ data }ResearchWebResponseitemscontent→snippet; addeddate,last_updatedsnippet, notcontentResearchEnrichResponseresearch_basis.citations→ top-levelcitations{ output, citations }flatResearchPeopleResultid,publishedDate,authorAlso restructures
ResearchAudienceResponse,ResearchInstagramPostsResponse, andResearchLookupResponseto match actual handler output (ported verbatim from #101).Error responses added
All 30
/api/research/*endpoints now document:Both reference the shared
ResearchErrorResponseschema.Test plan
research.jsonparses as valid JSONResearchErrorResponsecomponent present400and401entriesenum: ["success","error"]haveexample: "success"Note: the original PR also edited
cli.mdx; that change has already been handled onmainand is intentionally not re-applied here.Summary by cubic
Hardened the research API OpenAPI spec in
api-reference/openapi/research.jsonby fixing response schemas and adding standardized error responses. This aligns docs with real handler output and improves validation.New Features
ResearchErrorResponseand 400/401 responses to all/api/research/*endpoints./api/research/chartsquery params (ISO-2country,interval/typeenums with defaults,latestas boolean).schemafor/api/research/enrichto includetype: "object"andproperties; addedexample: "success"to allstatusfields.Bug Fixes
careerfield inResearchCareerResponse;snippet+date/last_updatedinResearchWebResponse; flattenedcitationsinResearchEnrichResponse; addedid,publishedDate,authorinResearchPeopleResult).ResearchAudienceResponse,ResearchInstagramPostsResponse, andResearchLookupResponseto reflect actual handler output.Written for commit 241fdea. Summary will update on new commits.
Summary by CodeRabbit
400and401status codes across endpoints.