The drawback is that the frontend now has its own schema, often it starts as a naive direct mapping of the real schema.
Thus any changes in the real schema also need to change the frontend schema and every use of it, or the mapping to the frontend schema needs to change.
Eventually these two schemas will diverge because it is not feasible that every schema change results in frontend change. Especially if the idea is to have two different teams working from either side, then the backend team can’t wait for the frontend team therefore the schema mapping will change.
And the thing is that the frontend shouldn’t be aware of how the backend schema is constructed, if the User model is separated into three different tables, because of some technical reason, that should not change how the frontend operates. The frontend understanding of what a User is shouldn’t be the same as the backends.
Therefore ideally frontend schema and the backend schema will always differ. They don’t view the world the same way.
However what you now have is a slow mapper between the frontend schema and backend schema.
The point of relationship databases is that you can view your data from different perspective by doing different SQL queries. That is already built in. But now we have invented yet another layer on top of SQL, usually in combination with the already monstrosity called ORM.
Especially in Oracle PL/SQL, I've seen this often abused to an extend where no one ever understood the whole business logic anymore (as logic was spread out in frontend, middle-layer services, and DB mumbojumo), and the database became a fragile core-piece (with a significant vendor login) and hindered all sort of future development.
Seriously, your business logic should be modelled in code, ideally in some sort of service layer (which does not necessarily mean microservices!).
That's not “abuse”. Admittedly, it's no longer an essential best practice for most systems, the way it used to be viewed, because it's more common to have a single application which fully owns the database and not to (at least in idealized theory, though very some ops staff still end up with direct access to the prod DB) allow access by other means, so in theory it doesn't tend to be necessary to avoid either circumvention of rules or (inevitably inconsistent, as well as expensive to maintain) duplication of logic.
This could be solved by only exposing stored procedures, but that just moves the code to the database server instead of the REST service with the same problems as before.
How does GraphQL make sure to respect table indexes? If not you get a super slow query.
You can get the same problems with GraphQL or stored procedures too of course, if the queries are not optimized correctly
And most of the projects I worked on in my professional career as a webdev, were replacing such workflow with a proper web application, because excel does not scale and eventually people fuckup their data.
Typical scenario for SPA is to use some sort of REST API, these API:s are usually designed for general usage, not specific usage, i.e. designed to be reused between components and views thus they basically return everything of a specific model regardless if data is needed or not.
Therefore the controller queries the database with the equivalent of SELECT * on a table (or perhaps multiple tables with joins) and then exposes every field.
And in many cases one request is not enough because the common generic design of REST APIs, thus a few request more are fired that results in multiple SELECT * against the database, and eventually the equivalent of SQL JOIN is performed in JavaScript.
Already SPA solution has an increased cost by asking for data that is currently not needed, not only in the traffic between the database and the backend but also in the traffic between the backend and the frontend.
And because we want to be good REST citizens we sprinkle the JSON payload with timestamps, resource urls and pagination information and what not and in majority of cases never to be used.
Comparing that to SSR where you can fetch what you need from the database with custom SQL query (I hope you do, otherwise the SQL leprechaun will make a visit).
Just imaging how much data there is on the web that is requested and then just discarded, not even looked at.
It is possible to design custom REST endpoints for each component, but then of course what is the point of a SPA then? If you are already writing a custom REST endpoint just return HTML instead of JSON and then swap in the new and swap out the old for your component (one-liner), the end result is the same.
SQL -> (Array of) object(s) -> JSON -> Javascript (Array of) object(s) -> HTML
can therefore be shortened to
SQL -> (Array of) object(s) -> HTML
3. That doesn't make any sense, number of languages are still the same regardless.