This is also exactly how I build Express APIs. One thing I'd add: when building an API, use Swagger (or something similar, but Swagger/OpenAPI have basically won, just do it). It makes API clients way, way easier to wrangle and removes a lot of the surprise from your application development. I sometimes forget that not everyone using React or Vue uses Swagger-based APIs that really do just kinda work, but they're a large part of why, for me, writing a fully-featured frontend is way better than entering Rails template hell or whatever. It's really, really easy: just a bit of state in the React component, kick off a fetch during componentWillMount, and drop a spinner that remains 'til you get an error or your data. If you're using TypeScript (and you should be), you'll have some pretty happy autocomplete based on the contents of your state and can just write code off the returned objects. Life's fun this way.
On the server side I use Express in Node and either `tsoa` or `inversify-express-utils`, while in Ruby I use my own Modern[0] library to autogenerate a Swagger document from the controllers I specify.
On the server side I use Express in Node and either `tsoa` or `inversify-express-utils`, while in Ruby I use my own Modern[0] library to autogenerate a Swagger document from the controllers I specify.
[0] - https://github.com/lukeautry/tsoa
[1] - https://github.com/inversify/inversify-express-utils
[2] - https://github.com/modern-project/modern-ruby