I think you've highlighted a big problem with SPAs in that they can encourage multiple API calls per user action. IMO, you should probably have a single endpoint per thing a user might do that might combine several conceptual APIs. i.e., if you have an API to add something to a list, have that API also return the current list.
They have a waterfall of multiple API requests by the browser to display a single page. That means the front end has a bunch of logic to aggregate and piece together requests. This in itself isn’t a big deal, if you move to doing it on the backend you still have the same logic and need to make the same sub requests.
Where it does become problematic is it leads to fat API endpoints sending far more data to the client than is needed. GraphQL lets you choose what fields you query but odds are there’s still data available you can ask for that shouldn’t be asked for and sent to a browser.
If your requests/aggregations are done serverside it gives you a better chance of filtering out data that should never be accessible in the browser. You can also make full use of Cache-Control headers and backend caching.
Creating individual endpoints for web apps went out of fashion as it involves more effort and people don’t like effort to do things well. I see it re-invented recently as backend-for-frontend.
> Creating individual endpoints for web apps went out of fashion as it involves more effort and people don’t like effort to do things well. I see it re-invented recently as backend-for-frontend.
Not true, individual endpoints requires more work for client side optimizations but the CRUD query mapping effort is not reduced with graphql. If anything, graphql endpoints require more effort on the backend side to build because of having to wire up the resolvers unless you are using something like Hasura.