On Sun, Oct 10, 2021 at 9:22 PM Christopher Dodunski (Tapestry) <
[email protected]> 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: [email protected]
> For additional commands, e-mail: [email protected]
>
>
--
Thiago