FastAPI (Python) or NestJS to produce self documented APIs via route annotations, handled by framework, and then from that, export an openapi file that you use to create the client in your necessary language. In so doing, every service I make can be commanded with ease by whoever wants to use it, at minimal overhead for me as the service maintainer.
It was a decent amount of effort to work out the bugs, enough so that I think better documentation around getting setup would be valuable, but of course the documentation is so cross-cutting that it’s difficult. But the work was well worth it—I’m much happier with this workflow where I don’t have to roll a service layer lib for my front end, nor use vanilla fetch libraries.
Perhaps you could clarify your criteria for usability further, but each of my service-client’s methods are 100% type-safe. This is because Nest and Fast encourage the use of (and subsequently export type information from) the DTO pattern. Service-clients constructors have plug-holes for obvious stuff like url & headers, you make API requests via method, I never feel that I’m needlessly repeating myself. Can’t imagine what else there is to meet usability needs, it works great, I can even make the method names pop out camel_case on the service client if I want to.
Perhaps my only gripe about the technique is that some request/response object types, specifically ones with recursive typing, become a hassle to code up as DTOs with the type annotations. I don’t understand why it’s a problem because it shouldn’t be, but it can knock you out of your flow if you don’t get it right the first time. The alternative, manually updating my service clients or using fetch libraries, is not type safe and thus is far worse, so frankly I’ll take it.