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 <
[email protected]> 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