Skip to content

Add /openapi endpoint using javalin-openapi-plugin#1058

Closed
EPNW-Eric wants to merge 3 commits intokomoot:masterfrom
EPNW-Eric:openapi
Closed

Add /openapi endpoint using javalin-openapi-plugin#1058
EPNW-Eric wants to merge 3 commits intokomoot:masterfrom
EPNW-Eric:openapi

Conversation

@EPNW-Eric
Copy link
Copy Markdown

@EPNW-Eric EPNW-Eric commented Apr 18, 2026

As requested in #550, this PR adds an OpenAPI endpoint. It does so by exposing the Photon API capabilities as an OpenAPI 3.x document at /openapi, using the javalin-openapi-plugin community library.

Changes

build.gradle

  • Added io.javalin.community.openapi:javalin-openapi-plugin:7.1.0: registers the /openapi route and generates the JSON spec at startup by reading compile-time metadata.
  • Added io.javalin.community.openapi:openapi-annotation-processor:7.1.0 as an annotation processor; this scans @OpenApi-annotated handlers during compileJava and emits the metadata the plugin reads at runtime.

App.java

  • Registers OpenApiPlugin in the Javalin config with title, version, and description.
  • Swaps the three GenericSearchHandler<T> route registrations for the new documented wrappers (see below), so the annotated handle() methods are what Javalin sees at each path.

New handler wrapper classes

  • Each implements Handler, delegates to GenericSearchHandler<T>, adds a @OpenApi annotation to handle()
  • ApiSearchHandler: documents /api (forward geocoding): all query parameters including q, lang, limit, lat/lon bias, bbox, countrycode, osm_tag, layer, include/exclude, dedupe, geometry, suggest_addresses, debug.
  • StructuredSearchHandler: documents /structured (structured forward geocoding): address component fields (city, street, postcode, etc.) plus the shared base parameters.
  • ReverseSearchHandler: documents /reverse (reverse geocoding): required lat/lon, optional radius, distance_sort, query_string_filter, plus the shared base parameters.

StatusRequestHandler

  • Added @OpenApi annotation to handle() to document the /status endpoint.

Why wrapper classes instead of annotating GenericSearchHandler directly

GenericSearchHandler<T> is reused for three different routes with different parameter sets. A single @OpenApi annotation on a class can only describe one path; the annotation processor links it to exactly one route. Three thin wrapper classes is the idiomatic solution - each has its own @OpenApi and delegates to the underlying generic handler, keeping all search logic in one place.

How to verify

./gradlew shadowJar
java -jar target/photon-1.0.0.jar -data-dir <path>
curl http://localhost:2322/openapi | jq .

The response should be a valid OpenAPI 3.x JSON document listing /api, /structured, /reverse, and /status with their query parameters and response schemas.


DISCLAIMER: All code in commit EPNW-Eric/photon@a0f4a94 as well as this PRs text were written by AI.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit a0f4a94. Configure here.

.description("Forward and reverse geocoder built on OpenStreetMap data.")
)
)
));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenAPI spec lists endpoints missing in reverse-only mode

Low Severity

When dbProperties.getReverseOnly() is true, the /api and /structured routes are not registered, but the OpenApiPlugin serves a compile-time-generated spec that always includes them. Users of a reverse-only deployment would see these endpoints in the /openapi document, attempt to call them, and receive 404 errors not mentioned in the spec.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit a0f4a94. Configure here.

@lonvia
Copy link
Copy Markdown
Collaborator

lonvia commented Apr 22, 2026

Thanks for that. Unfortunately, I've somewhat changed my mind on how to approach the OpenAPI issue and forgot to update #550 accordingly. Right now I'd prefer to go with the approach from #1038, i.e. having a formal OpenAPI spec separate from the service itself. So I'm going to close this.

Apologies for that. Your work is appreciated nonetheless.

@lonvia lonvia closed this Apr 22, 2026
@EPNW-Eric
Copy link
Copy Markdown
Author

No worries! Just that I understand it correctly: Will there be a formal OpenAPI spec and the code used by photon to expose the service generated based on it? Or will code and spec be decoupled and they both have to be keept in sync manually? Imo having them decoupled is cumbersome, so in my projects I usually write the OpenAPI spec first and by hand and use it as "ground of truth" to later use something like https://openapi-generator.tech/docs/generators/ to generate servercode from it.

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