Skip to content

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

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

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

Conversation

@neelneelneel

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 annotations in Semoss (reactors) and Monolith (REST resources). The TypeScript SDK in libs/sdk generates typed calls and a typed 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.

This change spans three repositories:

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

Changes Made

Semoss

  • AbstractReactor2<Input, Output>: a reactor declares its inputs once, as a record.
    • keysToGet, keyRequired, the key descriptions, the MCP types and the typed input all come from that record.
    • The return value is wrapped in a NounMetadata automatically.
    • --help, asMcpTool() and positional inputs still work.
  • Echo, GetCurrentInsightId and StopPixelExecution now extend it. Their outputs and messages are unchanged.
  • @Internal (prerna.openapi.Internal) marks a reactor or REST operation as not for general use. @DynamicOutput marks a reactor whose output type isn't fixed.
  • Adds the swagger-annotations-jakarta dependency and AbstractReactor2Test.

Monolith

  • OpenApiExporter and scripts/generate-api write target/generator/openapi.json. Nothing is listed by hand:
    • Published: every @Operation method in the servlets' JAX-RS applications, and every AbstractReactor2 (under x-semoss-pixels).
    • Left out: anything with swagger's @Hidden.
    • Tagged x-internal: anything with @Internal.
    • x-semoss-servlets names each servlet's SDK module.
  • The document is canonical, so repeated runs produce identical bytes. It is validated with swagger-parser, and the export fails on OpenAPI 3.0 forms, missing descriptions and duplicate operationIds.
  • GET /api/config is described by a ServerConfig record. ServerConfigContractTest keeps the record in step with the keys the resource actually returns. The response itself is unchanged.
  • An openapi Maven profile builds into target/openapi-build, so stale IDE output in target/classes can't shadow the Semoss jar.
  • Adds JUnit 5, OpenApiExporterTest with fixtures in test/openapi/fixtures, and docs/openapi.md.

semoss-ui (@semoss/sdk)

  • Generator: scripts/sdk-generator.
    • pnpm generate --openapi FILE writes src/generated/. Each call is a plain async function over the existing get/post, with its types written inline.
    • pnpm generate:check --openapi FILE reports drift.
    • The output is deterministic, whatever the document's key order or the machine's locale.
  • Generated calls: published as @semoss/sdk/api/*, starting with config from @semoss/sdk/api/monolith. Calls the backend marks internal get an @internal TSDoc tag.
  • Typed Pixels:
    • buildPixel and readPixelOutput, typed by the generated PixelCatalog. buildPixel writes every value as an escaped literal.
    • Typed overloads for runPixel, usePixel, useIteratorPixel, runPixelAsync and getPixelAsyncResult. Plain strings and explicit type arguments keep the legacy types.
  • Hooks:
    • useAPI(fn, input, options) passes an AbortSignal and compares its input by value.
    • useIteratorApi can now page a generated call directly: it fills in limit and offset and accepts a select function. 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 the document and regenerate the SDK:
    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

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.

1 participant