Path: ...!Xl.tags.giganews.com!local-1.nntp.ord.giganews.com!news.giganews.com.POSTED!not-for-mail NNTP-Posting-Date: Fri, 19 Apr 2024 18:48:40 +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 11:49:30 -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: Lines: 780 X-Usenet-Provider: http://www.giganews.com X-Trace: sv3-JJT6qqb5CS+wmLXoAh/TDPugsFvjoTuyaOljMiS1IQT7Lx8CV/g75S5/wFBuALDwgV/WIPvG97/LXP8!nwode08Ja7Jo7FpbjMElMbEBPU3Z2f3aVaVFFO6emt0Bh9BcrTOvJwuaOEtv4OWn4aLtPH/dmT2g!ow== 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: 30270 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 >> @GetMapping("/grp/{myGrpId}") >> @ResponseBody >> Rsp get1( >> @PathVariable("myGrpId") Pth pth, ========== REMAINDER OF ARTICLE TRUNCATED ==========