Skip to content

PoC: Built-in OpenAPI routing with controller.json#6248

Draft
joewiz wants to merge 4 commits intoeXist-db:developfrom
joewiz:feature/openapi-routing
Draft

PoC: Built-in OpenAPI routing with controller.json#6248
joewiz wants to merge 4 commits intoeXist-db:developfrom
joewiz:feature/openapi-routing

Conversation

@joewiz
Copy link
Copy Markdown
Member

@joewiz joewiz commented Apr 18, 2026

Summary

Add built-in OpenAPI routing to eXist-db via controller.json + api.json. Apps define REST endpoints declaratively in an OpenAPI 3.0 spec; eXist automatically routes requests to XQuery handler functions by operationId. This eliminates the need for Roaster and the controller.xql + api.xq + $lookup boilerplate.

What Changed

All new code is in the exist-services Maven module (not exist-core), per the architectural principle that exist-core should contain only the core database engine.

New classes in exist-services/

  • OpenApiServiceRegistry.java — in-memory routing table with path pattern matching
  • OpenApiServlet.java — dispatches matched routes to XQuery handlers
  • OpenApiStartupTrigger.java — scans /db/apps/ at startup for controller.json
  • OpenApiTrigger.java — collection trigger for auto-discovery on storage events

Configuration

  • web.xml — OpenApiServlet registration
  • controller-config.xml — URL pattern forwarding for /openapi/
  • conf.xml — startup trigger registration

Demo app

  • exist-core/src/test/resources/openapi-demo/ — three endpoints, no Roaster, no controller.xql

Architecture

controller.json (in app collection)
    └── references api.json (OpenAPI 3.0 spec)
            └── operationId: "prefix:functionName"
                    └── OpenApiServlet resolves to XQuery module + function
                            └── Handler returns map → servlet serializes as JSON

Relationship to PR #6247

This PR builds on #6247 (feature/builtin-package-api). Both share the exist-services module.

Test Plan

  • mvn install -pl exist-services -am -DskipTests compiles cleanly
  • Dashboard tests pass without Roaster installed
  • Apps using controller.json route correctly via OpenApiServlet

🤖 Generated with Claude Code

@adamretter
Copy link
Copy Markdown
Contributor

May I suggest that this should go into its own module. The exist-core module was created with the specific purpose of being slimmed down rather than made bigger, the previous plans was to remove everything from exist-core apart from core database engine.

joewiz and others added 4 commits April 19, 2026 12:44
…module

Add PackageManagementServlet, PackageService, and RepoPackageLoader in a new
exist-services Maven module (not exist-core) per the architectural principle
that exist-core should contain only the core database engine.

The exist-services module provides built-in HTTP services for the eXist-db
platform: package CRUD at /api/packages — list, get, install (registry +
upload), remove (with dependency checking), update-check, icon serving.
Compiled into the platform, no XAR dependency. Solves the self-upgrade problem
that existdb-packageservice had.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…PoC)

Proof of concept for OpenAPI-native routing in eXist-db. Apps can use a
declarative controller.json + OpenAPI api.json spec to define REST
endpoints without Roaster or controller.xql.

New components:
- OpenApiServiceRegistry: in-memory routing table with path pattern
  matching, scoped by collection
- OpenApiServlet: dispatches matched routes to XQuery handler functions
  via operationId resolution (prefix:local-name convention)
- OpenApiTrigger: collection-level trigger that discovers controller.json
  and api.json files and registers routes on storage events
- OpenApiStartupTrigger: scans /db/apps/ at startup for controller.json
  files and pre-registers routes

Demo app included in test resources (openapi-demo/) showing a minimal
app with controller.json + api.json + hello.xqm handler module.

PoC URL space: /exist/openapi/{app}/... (production will integrate with
/exist/apps/ via XQueryURLRewrite fallback)

This is Phase 2 of the OpenAPI-native routing initiative. See
taskings/openapi-native-routing-tasking.md for the full design.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The servlet was treating all map results as Roaster-style response maps
(with "code"/"body" keys), causing empty responses. Now it only treats
maps as response maps if they contain "code" or "body" keys; otherwise
it serializes them directly as JSON data.

Also sets output properties (method=json) before creating the serializer
and flushes the PrintWriter after serialization.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move OpenApiServlet, OpenApiServiceRegistry, OpenApiStartupTrigger, and
OpenApiTrigger from exist-core to exist-services per the architectural
principle that exist-core should contain only the core database engine.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joewiz joewiz force-pushed the feature/openapi-routing branch from 75aae5c to 97cde45 Compare April 19, 2026 16:45
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