On Tue, Oct 12, 2021 at 8:27 AM Dmitry Gusev <dmitry.gu...@gmail.com> wrote:

> Hi Thiago,
>

Hello!


> Sounds like a good tool when one needs to build something quickly.
> What I like the most from it is that it will be possible to reload
> implementation, including addition/removal of endpoints,
> which isn't possible with tapestry-resteasy singletons.
>

Yes, that's one of the main selling points for me.


> What I didn't see, but I assume it will be possible is `@Inject` of the
> endpoint "pages"?
> Say if we need to make a call from a test, or from another service?
>

The REST endpoint pages are ordinary Tapestry pages, so anything you could
do to test Tapestry pages you can use here too.


> Looking at the snippets it feels we could add support for JAX-RS
> annotations as syntax sugar,
> (similar to how `javax.inject.Inject` can be used instead of Tapestry's
> `@Inject`) so below snippet:
>

Reusing JAX-RS annotations is something I decided to not use to avoid
confusions. This is not a JAX-RS implementation, it doesn't look nor work
like one and I believe reusing its annotations would cause more confusion
than help. Also, you can use @StaticActivationContextValue with any event
handler method, REST or not, in pages or components.


> Devil's in details, of course, not sure if it's simple to implement, but
> seems feasible if we do this during class transformation.
>

Yep, discovery of event handler methods is done and cached during class
transformation. One of the many reasons Tapestry is fast. :)


> How can we control the format of `date` and `date-time` response fields,
> and format of the response objects in general?
>


> As far as I remember there's no built-in serialisation support for custom
> types -> Tapestry JSON objects.
>

Both questions above have the same answer: Tapestry's REST support doesn't
do object mapping (i.e. XML <-> POJO, JSON <-> POJO), but you should be
able to easily plug yours into it. For converting the request body to an
@RequestBody-annotated parameter, it uses the HttpRequestBodyConverter
service (which uses TypeCoercer as a fallback). You can plug your own by
implementing and contributing your own HttpRequestBodyConverter or by
adding coercions. For handling (and possibly converting and possibly also
setting additional HTTP headers) the object returned by event handler
methods, you can write your own ComponentEventResultProcessor.


> Do you assume users should build JSON instances explicitly?
>

No. I've just used Tapestry's own JSONObject and JSONArray in the examples
because they're already provided out-of-the-box, including coercions to and
from String.

The REST support doesn't assume anything of this kind. Actually, it doesn't
assume anything Tapestry 5.7 doesn't assume already. REST support assumes
what I've written in my last paragraph. Anyone should be able, for example,
to plug Jackson Databind (https://github.com/FasterXML/jackson-databind)
for doing Java to JSON conversions. In typical Tapestry fashion, it
provides a very flexible foundation for the developer to build on the top
of it, be it as a third-party library or custom code inside your project. I
should probably create an example for that in GitHub once I'm done.


> Also, it would be nice to have at least some basic support for input
> validation, in the format of ErrorObjects [1] maybe.
> Unsure if this is too much.
>

I believe that's better left for future third-party libraries built on the
top of Tapestry.

Thank you very much for your insightful feedback!


>
> [1] https://jsonapi.org/examples/#error-objects
>
> On Fri, Oct 8, 2021 at 11:12 PM Thiago H. de Paula Figueiredo <
> thiag...@gmail.com> wrote:
>
> > 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
> >
>
>
> --
> Dmitry Gusev
>
> AnjLab Team
> http://anjlab.com
>


-- 
Thiago

Reply via email to