Skip to content

feat: export the OpenAPI document the SDKs are generated from - #468

Open
neelneelneel wants to merge 3 commits into
devfrom
feat/autogenerate-api-in-sdk
Open

neelneelneel wants to merge 3 commits into
devfrom
feat/autogenerate-api-in-sdk

Conversation

@neelneelneel

@neelneelneel neelneelneel commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Description

The backend now owns the API contract, and the SDK is generated from it. Monolith exports one OpenAPI 3.1 document, built from its REST annotations and from every Semoss reactor. Each reactor's contract is inferred from what it already declares, and annotations refine it where inference can't see. The TypeScript SDK in libs/sdk generates typed REST calls and a types-only Pixel catalog from that document; a Python SDK can later read the same file.

Everything is opt-in. Existing SDK calls keep their behavior and types, and no reactor has to change to be published.

This change spans three repositories:

  • Semoss reads and annotates reactor contracts.
  • Monolith exports the document.
  • semoss-ui (@semoss/sdk) generates the calls and adds typed hooks.

Changes Made

Semoss

  • ReactorContract reads each reactor's contract from what it already declares. It constructs the reactor to do this but never executes it.
    • Inputs: keysToGet, by canonical name.
    • Required inputs: keyRequired. With none, nothing is required, which is how organizeKeys() checks at runtime.
    • Types: getKeyTypeForMCP.
    • Descriptions: getDescriptionForKey and getReactorDescription, with placeholders where they're missing.
  • Annotations in prerna.openapi:
    • @PixelOutput declares a reactor's output.
    • @PixelInput (repeatable) refines one input's type, item type, description or requiredness.
    • @Internal marks a reactor or REST operation as not for general use.
  • ReactorNames now holds the Pixel-name and frame-type rules, and ReactorFactory uses it too. Registration is unchanged.
  • Pilot reactors: Echo, StopPixelExecution and GetCurrentInsightId are annotated so their published types are pinned. An earlier AbstractReactor2 base class from this branch has been rolled back in favor of inference.
  • Adds the swagger-annotations-jakarta dependency and ReactorContractTest.

Monolith

  • OpenApiExporter and scripts/generate-api write target/generator/openapi.json. Nothing is listed by hand:
    • REST: every @Operation method in the servlets' JAX-RS applications is published.
    • Reactors: every general reactor is published under x-semoss-pixels. The ~150 frame-specific versions are left out, since the frame picks the implementation at runtime.
    • Opting out: swagger's @Hidden leaves a REST method or a reactor out.
    • Markers: @Internal adds x-internal (plus x-internal-reason when given). A contract with anything inferred gets x-semoss-inferred.
    • Modules: x-semoss-servlets names each servlet's SDK module.
  • Skipped reactors: a reactor whose contract can't be read is left out and listed with the reason in target/generator/skipped.txt. That covers a failing constructor, a duplicate key, a non-identifier name, or a name two classes share. The list is the same on every run. An annotated reactor that can't be read fails the export instead.
  • Validation: the document is canonical, so repeated runs produce identical bytes. It's checked with swagger-parser and rejected for OpenAPI 3.0 forms, missing descriptions and duplicate operationIds.
  • GET /api/config: described by a ServerConfig record. ServerConfigContractTest keeps the record in step with what the resource puts, and the response itself is unchanged.
  • Build: an openapi Maven profile builds into target/openapi-build, apart from IDE output in target/classes.
  • Adds JUnit 5, OpenApiExporterTest with fixtures (test/openapi/fixtures, test/openapi/badfixtures), and docs/openapi.md.

semoss-ui (@semoss/sdk)

  • Generator (scripts/sdk-generator):
    • pnpm generate --openapi FILE writes src/generated/. REST calls are plain async functions over the existing get/post, with inline types and TSDoc.
    • pnpm generate:check --openapi FILE reports drift without writing anything.
    • The output is deterministic, whatever the document's key order or the machine's locale.
    • Backend markers become TSDoc: @internal for x-internal, and a note on inferred reactors.
  • REST calls: published as @semoss/sdk/api/*, starting with config from @semoss/sdk/api/monolith.
  • Typed Pixels:
    • PixelCatalog is types only, so it adds no bundle size at any number of reactors.
    • buildPixel is checked against it at compile time and escapes every value.
    • readPixelOutput throws PixelError when the backend reported an error.
    • runPixel, usePixel, useIteratorPixel, runPixelAsync and getPixelAsyncResult get typed overloads. Plain strings and explicit type arguments keep the legacy types.
  • Hooks:
    • useAPI(fn, input, options) passes an AbortSignal, compares its input by value, and takes enabled.
    • useIteratorApi can page a generated call directly: it fills in limit and offset, accepts select, and starts again from page 0 when the input changes, with no deps array. The existing (fetchPage, options, deps) form still works.
  • Adds type-level tests (*.test-d.ts with tsconfig.typecheck.json) and @testing-library/react for the hook tests.

How to Test

  1. Install Semoss, run the Monolith tests, then export and regenerate:
    cd Semoss && mvn -q -DskipTests install
    cd ../Monolith && mvn -q -P openapi test
    scripts/generate-api --skip-semoss-install --sdk <path to semoss-ui>/libs/sdk

Add OpenApiExporter and scripts/generate-api, which write
target/generator/openapi.json. Nothing is listed by hand:
- every @operation method in the servlets' JAX-RS applications is
  published;
- every AbstractReactor2 is published under x-semoss-pixels;
- swagger's @hidden leaves an API out, and @internal adds x-internal.

The document is OpenAPI 3.1 and canonical: identical across runs, and
checked with swagger-parser. x-semoss-servlets names each servlet's SDK
module.

- Describe GET /api/config with a ServerConfig record, kept in step with
  the resource by ServerConfigContractTest.
- Add an openapi Maven profile that builds into target/openapi-build, apart
  from IDE output.
- Add JUnit 5 and OpenApiExporterTest with fixtures, and docs/openapi.md.feat(contracts): add typed record reactors and OpenAPI export
@neelneelneel
neelneelneel requested a review from a team as a code owner November 4, 2026 01:50
@snyk-io

snyk-io Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

⛔ Snyk checks have failed. 2 issues have been found so far.

Status Scan Engine Critical High Medium Low Total (2)
⛔ Open Source Security 0 2 0 0 2 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@neelneelneel

Copy link
Copy Markdown
Contributor Author

Depends on SEMOSS/semoss-ui#3850
Depends on SEMOSS/Semoss#3259
Depends on #468

neelneelneel and others added 2 commits November 3, 2026 21:50
OpenApiExporter now publishes every general reactor rather than only
AbstractReactor2 subclasses. Each contract is read with Semoss's
ReactorContract and refined by @PixelInput and @PixelOutput.

- Frame-specific reactors, the per-frame versions ReactorFactory keeps
  apart, are left out, and so are @hidden ones.
- A reactor whose contract cannot be read is left out and listed with the
  reason in target/generator/skipped.txt, the same on every run. That
  covers a failing constructor, a non-identifier key or name, and a name
  claimed by two classes. An annotated reactor fails the export instead.
- A contract with anything inferred is marked "x-semoss-inferred": true.
- Rewrite the fixtures as plain reactors (inferred, annotated, hidden,
  internal, unreadable, twice-named and frame-specific), add a failing
  fixture package, and update docs/openapi.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

2 participants