Path: Xl.tags.giganews.com!local-2.nntp.ord.giganews.com!news.giganews.com.POSTED!not-for-mail NNTP-Posting-Date: Sat, 20 Apr 2024 02:36:29 +0000 Subject: Re: Java HTTP API Signatures, schemas, XML and JSON, Pojo's and Poji's, Java and Spring and schema Newsgroups: comp.lang.java.programmer References: <2imdnULqbvFsBr_7nZ2dnZfqn_qdnZ2d@giganews.com> From: Ross Finlayson Date: Fri, 19 Apr 2024 19:37:31 -0700 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.6.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Message-ID: <3SGdnTa9B72zt777nZ2dnZfqnPWdnZ2d@giganews.com> Lines: 1263 X-Usenet-Provider: http://www.giganews.com X-Trace: sv3-Lx02+T2j3FMNApFfNzL4rxgyVg0dj6LHRdcFCt/9GO2ZqYqx6ibEatFqaym5VkDCh+LDC6vQ3QTWDvk!/xVPIvlk2COpqvz02QR/PFj2s0FRtSbOk1fEompT1EGAwIvmOPVIF8CRjaEoQWuP2zqnUOSs+YsC!tw== X-Complaints-To: abuse@giganews.com X-DMCA-Notifications: http://www.giganews.com/info/dmca.html X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly X-Postfilter: 1.3.40 Bytes: 52805 On 04/19/2024 01:48 PM, Ross Finlayson wrote: > On 04/19/2024 11:49 AM, Ross Finlayson wrote: >> On 04/19/2024 10:22 AM, Ross Finlayson wrote: >>> On 04/19/2024 09:30 AM, Ross Finlayson wrote: >>>> Signature API >>>> >>>> ccc.api >>>> ccc.api.exception >>>> ccc.api.fault >>>> >>>> ccc.api.client >>>> >>>> ccc.springsup.web >>>> >>>> ccc.serdes >>>> >>>> >>>> Api ApiMapping >>>> >>>> ApiFlt ApiHardFlt >>>> OtherCauseFault CovariantFault >>>> >>>> Pth Hdr Qpa Req Rsp Flt Err >>>> >>>> >>>> The other day I was writing a Spring Boot server, >>>> and the implementation of the Api looks like this >>>> >>>> For a service Srv, group of APIs Grp, and API Api >>>> >>>> public interface Srv { >>>> interface Grp { >>>> interface Api extends ccc.api.Api { >>>> >>>> static class Pth{} >>>> static class Qpa{} >>>> static class Hdr{} >>>> static class Req{} >>>> static class Rsp{} >>>> static class Flt{} >>>> static class Err{} >>>> >>>> >>>> Rsp api( >>>> @Valid @NotNull Pth pth, >>>> @Valid @NotNull Qpa qpa, >>>> @Valid @NotNull Hdr hdr, >>>> @Valid @NotNull Req req >>>> ) throws ApiFlt; >>>> >>>> } >>>> } >>>> >>>> } >>>> >>>> The validation annotations have to be on the root type, >>>> so, they go on the Api. >>>> >>>> public interface SrvMapping { >>>> interface Grp { >>>> @RequestMapping >>>> interface Api extends Srv.Grp.Api, ApiMapping { >>>> >>>> @Override >>>> @GetMapping("/api/{pth}") >>>> @ResponseBody >>>> Rsp api( >>>> @PathVariable Pth pth, >>>> @QueryParam Qpa qpa, >>>> @RequestHeader Hdr hdr, >>>> @RequestBody Req req >>>> ) throws ApiFlt; >>>> >>>> } >>>> } >>>> } >>>> >>>> The request mapping and also the openapi or documentation >>>> interfaces have to be on the interface the controller implements, >>>> and they don't mean anything to the Api, so they go on the ApiMapping. >>>> >>>> @Controller >>>> public class SrvController implements SrvMapping.Grp.Api >>>> { >>>> @Override >>>> Srv.Grp.Rsp api( >>>> Srv.Grp.Pth pth, >>>> Srv.Grp.Qpa qpa, >>>> Srv.Grp.Hdr hdr, >>>> Srv.Grp.Req req >>>> ) throws ApiFlt; >>>> } >>>> >>>> The controller just implements the Api, Spring Web wires >>>> it up and Openapi documents it up. >>>> >>>> And it results sort of thusly a very simple organization of APIs. >>>> >>>> public interface Srv { >>>> >>>> interface Grp1 { >>>> interface Api1 { /* */ } >>>> interface Api2 { /* */ } >>>> interface Api3 { /* */ } >>>> interface Api4 { /* */ } >>>> } >>>> interface Grp@ { >>>> interface Api1 { /* */ } >>>> interface Api2 { /* */ } >>>> interface Api3 { /* */ } >>>> interface Api4 { /* */ } >>>> } >>>> /* */ >>>> } >>>> >>>> The key is that given those, the Api and ApiMapping an entire >>>> Signature, of the mapping, sort of results, with adding this >>>> sort of ApiStatusMapping, to relate the HTTP status codes, >>>> with, the covariant return bodies, then it's sort of all one thing. >>>> >>>> ("a functional interface may still have multiple default methods ...") >>>> >>>> The idea is that the interfaces carry very well down from these. >>>> >>>> For most often usual "APIs" these days it'd often look: >>>> >>>> @Data >>>> static class MyGrp { >>>> >>>> } >>>> >>>> public interface Srv { >>>> interface Grp { >>>> interface Get1 extends ccc.api.Api { >>>> >>>> static class Pth{ String myGrpId;} >>>> static class Req extends MyGrp{}; >>>> static class Rsp{} >>>> static class Flt{} >>>> static class Err{} >>>> >>>> Rsp get1( >>>> @Valid @NotNull Pth pth, >>>> @Valid @NotNull Req req >>>> ) throws ApiFlt; >>>> >>>> } >>>> interface Put1 extends ccc.api.Api { >>>> >>>> static class Pth{ String myGrpId;} >>>> static class Req extends MyGrp{} >>>> static class Rsp{} >>>> static class Flt{} >>>> static class Err{} >>>> >>>> Rsp put1( >>>> @Valid @NotNull Pth pth, >>>> @Valid @NotNull Req req >>>> ) throws ApiFlt; >>>> >>>> } >>>> } >>>> >>>> } >>>> >>>> >>>> public interface SrvMapping { >>>> interface Grp { >>>> @RequestMapping >>>> interface Api extends Srv.Grp.Get1, ApiMapping { >>>> >>>> @Override ========== REMAINDER OF ARTICLE TRUNCATED ==========