I'm sorry, I forgot to include the logic for Swagger/OpenAPI message and configuration symbol lookups: Running the webapp with logging at debug level, you'll see entries from DefaultOpenApiDescriptionGenerator showing the message keys and configuration symbols being looked up.
- Everything is looked up by message first, configuration symbol second. Symbols use the tapestry.[message key] format. - Exception: openapi property is only looked up by symbol - When building a message key, if it's based on a path, the starting slash isn't removed. - Example: openapi./something.head.summary - When building a message key, HTTP method names are lowercased. - openapi: - tapestry.tapestry.openapi-application-version (no message lookup) - info.title: - tapestry.openapi-title - info.description - tapestry.openapi-description - servers 1. BaseUrlSource.getBaseUrl(false) (base HTTP URL) 2. BaseUrlSource.getBaseUrl(true) (base HTTPS URL) - tags. One tag automatically generated tags for each page: - name: 1. openapi.[fully qualified class name].tag.name 2. openapi.[class name].tag.name 3. Class name (unchanged, not looked up) - description: 1. openapi.[fully qualified class name].tag.description 2. openapi.[class name].tag.description - Each page tag is automatically applied to all paths handled by the page. - paths property (REST endpoints). For each path: - summary: *openapi.[path].[HTTP method].summary - description: *openapi.[path].[HTTP method].summary - responses. For each response: - description 1. openapi.[path].[HTTP method].response.[HTTP status code] 2. openapi.[fully qualified class name].[HTTP method].response.[HTTP status code] 3. openapi.[class name].[HTTP method].response.[HTTP status code] 4. openapi.[HTTP method].response.[HTTP status code] 5. openapi.response.[HTTP status code] On Fri, Oct 8, 2021 at 7:04 PM Thiago H. de Paula Figueiredo < thiag...@gmail.com> wrote: > Hello, Tapestry community! > > I've been working on something I really wanted Tapestry to have but > haven't had a chance to implement myself until some time ago: proper REST > support. And not do it by integrating with some other framework like Jersey > or CXF or by being a JAX-RS implementation, but by doing it in a very > Tapestry way: event handler methods, TypeCoercer for type conversions, > everything being customizable by contributions to Tapestry-IoC services, > return value of event handler methods handled by > ComponentEventResultProcessor implementations, etc. > > This is a work in progress, done in the "rest" branch, so I decided to > publish a snapshot (5.8.0-SNAPSHOT) so you can use it yourself and tell me > what you feel about it. All feedback is welcome! > > Major points: > > - New page-level events are triggered after the "activate" event is > triggered (i.e. onActivate()) so you can write REST endpoints as regular, > live-class-reloaded event handler methods. > - One for each supported HTTP method: GET, POST, DELETE, PUT, HEAD, > PATCH. > - Event name is onHttp[method name]. For example, onHttpPut. > - New constants in EventConstants for each supported HTTP method. > - Activation context for REST event handler methods exactly in the > same way as in onActivate(). > - Just like onActivate(), these new events are not triggered in > components. > - New service in tapestry-http (which is included by tapestry-core), > RestSupport, with utility methods and <T> Optional<T> > getRequestBodyAs(Class<T> type), which returns the request body converted > to a given type. > - getRequestAsBody(Class) uses HttpRequestBodyConverter. > - Another new service in tapestry-http, HttpRequestBodyConverter, > which uses an ordered configuration of itself, which provides conversions > of request body to given types. > - Only one method, <T> T convert(HttpServletRequest request, > Class<T> type); > - tapestry-http contributes one implementation, which is added as > the last one in the ordered configuration, which uses TypeCoercer. > - Out of the box, it supports conversions to String, primitive > types, JSONArray, JSONObject plus any other type that has a String -> > type > conversion available in TypeCoercer, directly or not. > - New annotation for page event handler method (onActivate(), onHttp*) > parameters: @RequestBody, which receives the request body and converts it > to the parameter type using RestSupport.getRequestAsBody(). > - Think of it as @RequestParameter but for the request body instead of > a query parameter. > - Example below. > - New annotation for page event handler method (onActivate(), onHttp*) > parameters: @StaticActivationContextValue("something"), for defining that > method will only be called if that page activation context value matches a > given string. > - Example below. > - Parameters with that annotation still get their values set as > usual. > - This was built mostly for REST support, but it can useful for > non-REST situations too when a give activation context has a number of > possible values and there's some logic tied to it. > - Automatic generation of Swagger/OpenAPI 3.0 REST API definition > files. > - OpenApiDescriptionGenerator service, which is an ordered > configuration of itself. > - An internal implementation generates a base JSON object > definition that can be customized by contributing more > OpenApiDescription > implementations. > - Titles, names, summaries, etc can be provided by configuration > symbols or message files (app.properties). > - Messages files are live class reloaded too, so all changes > done to the REST endpoint event handler methods and the corresponding > messages are live reloaded. > - Formats for message keys and described below. > - Parameter descriptions not implemented yet. > - It will support query parameters and path parameters. > - [Not implemented yet] Embedded Swagger/OpenAPI viewer (i.e. the > right pane of https://editor.swagger.io) hooked directly to the > definition file generated by OpenApiDescriptionGenerator > - It's going to be a separate subproject/JAR to avoid bloating > projects not using the viewer > > > @StaticActivationContextValue example: > > final private String COMPLETED = "completed"; > final private String CLOSED = "closed"; > // Only called if first page activation context value is "completed" > > @OnEvent(EventConstants.ACTIVATE) > void completed(@StaticActivationContextValue(COMPLETED) String state, > int id) { > ... > } > > // Only called if first page activation context value is "closed" > @OnEvent(EventConstants.ACTIVATE) > void closed(@StaticActivationContextValue(CLOSED) String state, int > id) { > ... > } > > REST endpoint event handler method example: > > Object onHttpPatch( > @StaticActivationContextValue("subpath") String subpath, > String parameter, > @RequestBody String body) > { > ... > } > > @OnEvent(value = EventConstants.HTTP_DELETE) > Object delete(@StaticActivationContextValue("subpath") String subpath, > String parameter) > { > return createResponse(EventConstants.HTTP_DELETE, null, parameter); > } > > Happy coding! > > -- > Thiago > -- Thiago