Files
Flash5/flash-extensions/flash-ext-openapi/README.md
T
Zakaria El Orche 9d39e24ccb refactor(ext-auth): generic sessions, shared annotation wiring, rename to flash-ext-auth-oidc
AuthMiddleware.install(ctx, config, source) now owns the annotation processor and
the flash.auth.policy key, so a second credential source gets annotation-driven
authorization without copying the wiring. The key is public: an extension that
contributes middleware can order itself around authentication.

OidcSession becomes Session in auth-core, carrying claims, an expiry and an opaque
attribute map. OpenID Connect keeps its access, id and refresh tokens in that map
under its own keys, so renewal stays its business and core has no OAuth2 vocabulary
in it. isAccessTokenExpired() becomes isExpired(), with the 30s eager-renewal
window it always had and now a test for it.

flash-ext-oidc is renamed flash-ext-auth-oidc, matching cache-core/cache-caffeine
and data-core/data-hibernate.
2026-09-10 19:06:15 +00:00

3.9 KiB

flash-ext-openapi

OpenAPI 3.0.3 generation + Swagger UI for Flash.

What it provides

Route Description
GET /openapi.json OpenAPI spec JSON
GET /openapi.yaml OpenAPI spec YAML
GET /openapi/swagger Swagger UI

Install

FlashApp.create(8080)
    .install(new JacksonExtension())
    .install(new OpenApiExtension("/openapi", "My API", "1.0.0"))
    .scan("com.acme.handlers")
    .startAndBlock();

Operation annotation

@GET("/users/{id}")
@ApiOperation(summary = "Get user", description = "Returns one user", tags = {"users"})
@Parameter(name = "expand", in = ParameterIn.QUERY, type = SchemaType.STRING, examples = {"roles", "permissions"})
@APIResponse(
    responseCode = "200",
    description = "User found",
    content = @Content(contentType = ContentType.JSON, schema = UserDto.class)
)
public final class GetUser extends RequestHandler { ... }

Response patterns

Single object

@APIResponse(
    responseCode = "200",
    description = "User found",
    content = @Content(contentType = ContentType.JSON, schema = UserDto.class)
)

Array

@APIResponse(
    responseCode = "200",
    description = "Users listed",
    content = @Content(contentType = ContentType.JSON, schema = UserDto.class, array = true)
)

No content

@APIResponse(
    responseCode = "204",
    description = "Deleted",
    content = @Content(contentType = ContentType.NONE)
)

Inferred from handler return type

@APIResponse(
    responseCode = "200",
    content = @Content
)

If content.schema is omitted, schema is inferred from the handler handle(...) return type. Explicit content.schema always wins over inference.

Inference defaults:

  • UserDto -> object schema for UserDto
  • List<UserDto> / Set<UserDto> / UserDto[] -> array with items: UserDto
  • Map<String, UserDto> -> object with additionalProperties: UserDto

DTO schema metadata

@Schema(name = "User", title = "User DTO", description = "Public user", deprecated = false)
public class UserDto {

    @SchemaProperty(title = "ID", required = true, example = "USR-100", enumeration = {"USR-100", "USR-101"})
    public String id;

    @SchemaProperty(hidden = true)
    public String internalDebug;
}

Supported field-level exclusion:

  • @Schema(hidden = true) / @SchemaProperty(hidden = true)
  • @JsonIgnore
  • @JsonIgnoreProperties(...)
  • transient / static

Contributor API

OpenAPI is extension-agnostic. Other extensions contribute with OpenApiContributor via OpenApiContributorRegistry.

Supported contribution surfaces:

  • components fragments (merged with last-wins)
  • operation security requirements (additive)
  • operation responses and response headers (additive)

Merge policy:

  • contributor collisions use last-wins
  • manual @APIResponse description always wins over contributors for the same status

OIDC interop

When flash-ext-auth-oidc is installed, OpenAPI integrates automatically:

  • security scheme under components.securitySchemes
  • per-operation security
  • auto responses (class-based handlers):
    • 401 Authentication required
    • 403 role/scope required messages when applicable

Manual @APIResponse for the same status code always wins.

Limiter interop

When flash-ext-limiter is installed, handlers with @Limit automatically get response headers documented in OpenAPI:

  • X-RateLimit-Limit
  • X-RateLimit-Remaining
  • X-RateLimit-Reset
  • Retry-After on 429

If 429 is missing, it is auto-added as Too Many Requests.

Notes

  • Operations are collected from final boot-time routes for class-based handlers with @ApiOperation.
  • Documented paths always match runtime paths (including scope namespaces/prefixes/rewrites).
  • Route path params are auto-discovered from /{id}.
  • Parameter annotations are mainly for query/header/cookie enrichment.
  • Output responses are sorted by numeric status code.