Skip to content

UN-4009 [MISC] Generate and commit the API deployment OpenAPI spec in-repo - #2237

Open
chandrasekharan-zipstack wants to merge 7 commits into
mainfrom
feat/docstudio-openapi-spec
Open

UN-4009 [MISC] Generate and commit the API deployment OpenAPI spec in-repo#2237
chandrasekharan-zipstack wants to merge 7 commits into
mainfrom
feat/docstudio-openapi-spec

Conversation

@chandrasekharan-zipstack

@chandrasekharan-zipstack chandrasekharan-zipstack commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

What

The OpenAPI description of the API deployment execute / status endpoints is now generated and committed in this repository, and a test fails when it drifts from the code. drf-yasg, which generated nothing anyone read, is removed.

Why

The published Python client and the SDK generated for it are built from that description. It was produced by a script living outside this repository, so a route, serializer or response change here could silently invalidate it — the breakage would surface later, in a client repo, against a spec nobody in the PR could see.

How

  • drf-spectacular added as a backend dependency; DEFAULT_SCHEMA_CLASS and SPECTACULAR_SETTINGS set in settings/base.py. Both are read only during schema generation — no request-time behaviour changes.
  • api_v2/openapi_schema.py holds the schema annotation. The introspected schema is wrong in ways that matter to a generated client: a bare FileField maps to format: uri (right for output, wrong for a multipart upload), result: null while an execution is pending crashes a generated deserialiser without allow_null, and operation_id / tags decide the command names and module paths clients expose. It is a module of its own rather than part of serializers.py, because none of these serializers parses a request or builds a response.
  • api_v2/deployment_spec_urls.py — a urlconf mirroring the real mount. Generating against the included sub-urlconf drops the prefix and produces paths the server does not serve. SPEC_URLCONFS is a tuple: widening the spec to another endpoint is one entry plus its @extend_schema.
  • manage.py generate_docstudio_spec writes specs/docstudio-oss.json with sorted keys, so the committed file is a usable drift signal. --check fails instead of writing.
  • api_v2/tests/test_docstudio_spec.py regenerates and compares, and checks every documented operation resolves to a served URL, declares the deployment key, and documents the failures a client will branch on. It runs in the existing unit-backend group — no database, no new CI job. Its failure message names the repos that regenerate from the spec, since propagating the change downstream is the part CI cannot do.
  • drf-yasg and the docs app removed. The redoc UI they served was built with public=False and no endpoint carried a @swagger_auto_schema, so an anonymous caller saw an empty schema. Nothing generated or consumed it.

Regenerating

uv run python manage.py generate_docstudio_spec

from backend/, then commit. The test says so in its failure message, along with the client and CLI repos that regenerate from the result.

Can this PR break any existing features

The /doc/ route is gone with drf-yasg, and drf-spectacular serves no UI in its place — the spec is a committed file, not an endpoint. Nothing else changes at request time: the two new settings are read only during schema generation, and no route, serializer or response is modified. The annotation is metadata on the view, not behaviour.

Database Migrations

None.

Env Config

None.

Notes on Testing

666 passed, 1 skipped in the backend unit tier this lands in, including the new spec tests. The generated spec is byte-identical to what the external script produced, apart from the root tags array — clients had nowhere to read group descriptions from, which is the one deliberate addition.

Related Issues or PRs

🤖 Generated with Claude Code

https://claude.ai/code/session_014f9oEEYspPH4fmPULTnLkJ

The published Python clients and their generated SDKs are built from a spec of
the deployment execute/status endpoints, which until now was produced by a
script living outside this repo — so a route or serializer change here could
silently invalidate it.

The schema annotation for DeploymentExecution now lives next to the view, and
`manage.py generate_docstudio_spec` writes specs/docstudio-oss.json. A unit
test regenerates and compares, so drift fails in this repo's existing CI tier
rather than in a client repo, with no database or extra CI job needed.

The generated spec is unchanged from what the external script produced, apart
from a root `tags` array — clients had nowhere to read group descriptions from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014f9oEEYspPH4fmPULTnLkJ
The committed spec is what published clients are generated from, so the
places where it disagreed with the server are places every SDK inherits.

- Declare the bearer scheme the endpoints enforce. DRF's unset
  authentication default was being introspected as a decision and
  published session and basic auth, which these endpoints do not accept.
- Declare the failures a caller has to handle (400/401/403/404/409/429)
  and describe the 406, so a generated client can branch on them.
- Derive the response model from the serializer that builds the response,
  which drops `workflow_id` -- a field no code path produces.
- Stop shadowing `files`: the real field carries the binary annotation, so
  a change to it now moves the spec.
- Drop the MCP operations. MCP speaks JSON-RPC over one POST, so it had no
  REST shape to describe and was published with guessed responses, no
  security, and an internal docstring as its description.
- Say in the shipped text that a status read is one-shot, and that
  documents may be supplied as files or presigned URLs.

The gate had the same blind spots. It now resolves the real mount instead
of comparing against a hand-written copy of it, fails when the generator
reports a diagnostic instead of certifying its guess, and asserts the auth
scheme and error statuses. Verified by mutation: moving the mount, adding
a response field, changing the `files` constraint and dropping the auth
annotation each redden the suite, and none of them did before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014f9oEEYspPH4fmPULTnLkJ
The deployment endpoints are the public API surface, and the generated
clients carry this title into their own documentation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014f9oEEYspPH4fmPULTnLkJ
The spec describes one endpoint today, and five of these tests read it by
unpacking a single item or by indexing get and post directly. The first
endpoint added turns all five red for no reason, and a GET-only one
raises KeyError. They now walk whatever the spec documents. The drift and
diagnostics gates are unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014f9oEEYspPH4fmPULTnLkJ
@chandrasekharan-zipstack
chandrasekharan-zipstack marked this pull request as ready for review August 17, 2026 16:06
@greptile-apps

greptile-apps Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR replaces the legacy runtime API documentation setup with a committed, reproducibly generated OpenAPI contract for deployment execution endpoints.

  • Adds drf-spectacular configuration, endpoint annotations, and schema-only serializers.
  • Adds a management command and tests that detect schema drift and invalid documented routes.
  • Commits the generated DocStudio OpenAPI specification and removes the unused drf-yasg documentation route.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
backend/api_v2/openapi_schema.py Defines client-facing request, response, authentication, operation, and error metadata for the deployment execute and status endpoints.
backend/api_v2/management/commands/generate_docstudio_spec.py Generates a deterministic committed schema and provides a non-writing drift-check mode.
backend/api_v2/deployment_spec_urls.py Selects the deployment route from the served root URL configuration so generated paths retain their real mount prefix.
backend/api_v2/tests/test_docstudio_spec.py Verifies committed-schema drift, route reachability, authentication metadata, operation coverage, failure responses, and response-field compatibility.
backend/api_v2/serializers.py Adds schema metadata that represents multipart uploads as binary without changing request validation behavior.
backend/backend/settings/base.py Configures drf-spectacular as DRF's schema generator and removes the legacy documentation app configuration.
backend/pyproject.toml Replaces drf-yasg with a pinned drf-spectacular dependency to keep committed schema rendering deterministic.
specs/docstudio-oss.json Commits the generated OpenAPI contract consumed by downstream deployment clients.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Runtime[Deployment views and serializers] --> Generator[drf-spectacular SchemaGenerator]
  Routes[Deployment spec URLconf] --> Generator
  Annotations[OpenAPI annotations] --> Generator
  Generator --> Spec[specs/docstudio-oss.json]
  Generator --> DriftTest[Schema drift tests]
  Spec --> DriftTest
  Spec --> Clients[Published client and generated SDK]
Loading

Reviews (2): Last reviewed commit: "test: name the downstream repos in the d..." | Re-trigger Greptile

@chandrasekharan-zipstack chandrasekharan-zipstack changed the title feat(api): generate and commit the API deployment OpenAPI spec UN-4009 [MISC] Generate and commit the API deployment OpenAPI spec in-repo Aug 17, 2026
The `docs` app served a redoc UI over a schema drf-yasg introspected with
`public=False`, so an anonymous caller saw nothing and no endpoint carried a
`@swagger_auto_schema` annotation. Nothing generates or consumes it.

Removes the dependency, the `docs` app and its two mounts. The `/doc/` route
goes with it; drf-spectacular serves no UI, only the committed spec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFSunNN6RKRA1xo6kWkztx
The annotation serializers exist only to shape the published spec, so they
sit in `api_v2/openapi_schema.py` rather than in `serializers.py`, where a
request-time import of one would look ordinary. `api_deployment_views.py`
keeps a single decorator.

`deployment_spec_urls.py` now selects mounts from a tuple, so widening the
spec to another endpoint is one entry plus its `@extend_schema`.

The generated spec is unchanged: component names are all that reach it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFSunNN6RKRA1xo6kWkztx
…ponse fields

The drift test is the only gate, so its message has to reach the person or
agent who then has to regenerate the client and the CLI; it now names both
repos, as does the management command's `--check`.

Adds one binding the annotation could not express by inheritance: the view
returns the execution DTO as a dict rather than through
`APIExecutionResponseSerializer`, so a renamed DTO field would reach clients
as a field the server never sends.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFSunNN6RKRA1xo6kWkztx
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
e2e-api-deployment e2e 3 0 0 0 20.8
e2e-coowners e2e 1 0 0 0 1.3
e2e-etl e2e 1 0 0 0 8.3
e2e-login e2e 2 0 0 0 1.2
e2e-prompt-studio e2e 1 0 0 0 4.4
e2e-smoke e2e 2 0 0 0 2.2
e2e-workflow e2e 1 0 0 0 16.5
integration-backend integration 290 0 0 26 44.7
integration-connectors integration 1 0 0 7 7.8
integration-workers integration 140 0 0 1 49.4
unit-backend unit 1009 0 0 1 41.7
unit-connectors unit 63 0 0 0 9.9
unit-core unit 33 0 0 0 1.4
unit-platform-service unit 15 0 0 0 2.6
unit-rig unit 117 0 0 0 5.4
unit-sdk1 unit 518 0 0 0 26.2
unit-workers unit 1346 0 0 1 103.7
TOTAL 3543 0 0 36 347.6

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • adapter-register-llm — covered by integration-backend
  • workflow-author — covered by integration-backend
  • co-owner-manage — covered by integration-backend, e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-provision — covered by integration-backend
  • api-deployment-auth — covered by integration-backend
  • api-deployment-run — covered by e2e-api-deployment
  • mcp-server-auth — covered by integration-backend
  • mcp-platform-auth — covered by integration-backend
  • prompt-studio-author — covered by integration-backend
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • connector-register-test — covered by integration-backend
  • pipeline-etl-execute — covered by e2e-etl
  • usage-aggregate-read — covered by integration-backend
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant