On Sun, Oct 10, 2021 at 9:22 PM Christopher Dodunski (Tapestry) < chrisfromtapes...@christopher.net.nz> wrote:
> Hi Thiago, > Hello! > This sounds like an interesting work, Thiago. Thanks! I know it's been very interesting work for me to implement so far. :D > I spent a fair amount of > time getting my web application to push updates out from a Tapestry > Service via WebSocket, Interesting. A Tapestry (probably Tapestry-IoC, actually) integration with WebSocket is something I have in my mental backlog but couldn't investigate yet. > but it would be great having the RESTful option > too (for a possible, future mobile app). And all without having to > employ an additional framework such as Spring REST. > Indeed. And it also has the advantage of reusing what you already know about Tapestry, so you'd need to learn just a bit of new stuff instead of a whole other framework. > > Kind regards, > > Chris Dodunski. > > > On 2021-10-09 11:04, Thiago H. de Paula Figueiredo 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 > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@tapestry.apache.org > For additional commands, e-mail: dev-h...@tapestry.apache.org > > -- Thiago