On Fri, Oct 8, 2021 at 11:02 PM Qbyte Consulting <qbyteconsult...@gmail.com> wrote:
> Hi, > Hello! > Maybe I’m not getting something here. > A RESTful service is supposed to provide business entity oriented > interfaces with CRUD like functionality. Yeah, I'm thinking we have a concept mismatch here. I'm thinking of REST as a way to build and describe APIs accessed through HTTP(S), like its original definition cited in https://en.wikipedia.org/wiki/Representational_state_transfer. For example, if you want to make a request that deletes something, you use the DELETE HTTP method. The definition you wrote above is way narrower than the one I'm using. > Tapestry provides front end oriented interfaces to support page views. I'm afraid I'll disagree with you here. Tapestry definitely does that (specifically, the page/component framework), but it was never limited to that. One of the changes introduced in version 5.7 is exactly moving the HTTP request handling parts of Tapestry (RequestFilter, Dispatcher, etc) to tapestry-http while the front-end specific code (support for pages, components and assets) remained in tapestry-core. This way, you can use Tapestry without including the front-end (i.e. pages and components) part. Since Tapestry's inception, more than 15 years ago, you could create a page that could return any kind of response by creating an onActivate() method returning a StreamResponse instance. And there's also Tapestry-IoC, which can be used without anything web-related. You could definitely handle REST-style requests in Tapestry before, but in a very clumsy way (having to check Request.getMethod() explicitly, no support for static activation context values, no support for reading the body of a request, etc). The REST support being introduced here is to make this almost as easy as writing on onActivate() method. > There’s a huge difference in implementation. > Actually, no. REST endpoints are regular page event handler methods. The basic difference is that there are new, more specific events being triggered, plus a few other small features to make it easier to deal with REST requests. > > GraphQL is more oriented towards supporting front end requirements. > > John > > Sent from my iPhone > > > On 9 Oct 2021, at 05:12, 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 > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@tapestry.apache.org > For additional commands, e-mail: dev-h...@tapestry.apache.org > > -- Thiago