Don’t we all just want to use SQL on the front end?
vjpr.medium.com
vjpr.medium.com
But... it seems like if you're willing to expose your data model to the client, then it seems like some combination of code signing the SQL (with parameters left empty) along with the acceptable list of named parameters, e.g.:
Signed blob:
{
sql: "SELECT name, email, ... FROM users WHERE users.id = %(userid)s"
allowedParameters: []
}
Such that the client is allowed to send this query, but they're not allowed to provide any parameters, the backend has to provide the userid. That seems workable to me.Likewise:
{
sql: "SELECT order.price, order.... FROM orders WHERE orders.user_id = %(userid)s AND orders.id = %(orderid)s"
allowedParameters: ["orderid"]
}
This would allow the frontend to provide an order ID, but not the user ID - so the user still can't look at other people's orders and if not logged in, it's an invalid query without a userid. And the client isn't allowed to change the "sql" or parameters sent or the signature is invalid.Edit: Someone else replied that if you have sufficiently advanced build tooling, you can statically extract the SQL/GraphQL from the client side code and replace them with IDs, and then move the SQL to the backend. That's very cool, but the average startup isn't using bazel/buck/etc. Those tools aren't yet small app friendly enough (which is unfortunate, IMO.)
Or...you could just expose a schema with views and sprocs where their definitions use only the SQL you are comfortable with against the base tables, which live off in their own schema isolated from external users. Same effect, but doesn’t require a whole new custom layer on top to reimplement what has been a basic feature of RDBMS engines for decades.
But I haven't actually seen a codebase that does this, so maybe I'm wrong. Have you used this approach in a project with more than a few developers and a large database? How did it go?
Another way to look at it is that changing the database schema is already a problem for the API which has to talk to it, so you're not really saving yourself any work by putting an extra layer between the frontend and the database.
In fact, if anything, you're doubling the amount of work, because there are now two interfaces (DB to API, and API to frontend) whose backwards compatibility you have to worry about.
If you have 100 other teams each with 5+ developers consuming your API -- or especially if your API is a product -- then keeping the API to frontend interface relatively stable with rare breaking changes is much more valuable than saving yourself even a major time commitment on DB to API work.
On the other hand, if you have relatively few clients -- or if the clients are "lower status"/"cheaper" teams -- saving time on the DB to API work a the expense of client teams might make sense.
It might actually be quite easy to version an SQL api, because you have the DDL migrations files and could actually make things backwards compatible to some degree. You would have a translation layer to modify the queries. Of course, your migrations would need to be more detailed tracking how things map to each other. But probably it would get too complex in the end. But not that much different to changes to a REST api really.
But, yeah, this happens with REST APIs too.
The middleware doesn’t do anything except populate query parameters and do a bit of sanity checking.
That said, I guess you could just add row / column ACLs to the database user, and then map the database user to the app user.
Server sends the query so server can send the signature hash with it, so the server signs the query with the server's key and sends both query and signature.
If the server ever receives a query without a signature or with a signature that is incorrect it can ignore or generate an error.
We’ve taken this approach for implementing database queries in Lowdefy [0] (SQL support will be live in next version, implementation using knex [1]. Also a “shared state” between backend and frontend makes parsing paramaters to queries on the backend really seamless and in return a great dev experience. Also allows to to only parse some parameters like secrets only on the backend.
What we are experiencing with Lowdefy apps is that bringing the data model closer to the UI makes coding and UI maintainability of simple projects very easy. This approach works exceptional for us in the BI reporting space where you primarily aggregate data.
However as soon as you move out of the CRUD space to more complex backend logic, extracting the logic to a single interface again simplified the implementation a lot, in fact apps very quickly becomes hard to maintain in my experience.
This does not mean that there is no place for easy CRUD dev tools like OP, but I do believe that an API like solution is required when life gets more complex or even just transactional. But there is also more creative ways to solve this problem.
[0] - https://github.com/lowdefy/lowdefy [1] - https://github.com/knex/knex
Yeh, that's the best idea. A babel plugin could do it easily. I already have have watcher script calling `graphql-codegen` to add types to my graphql queries, which works fine in the workflow.
I get WHY you'd want to be able to throw in any random filter/sort to get the exact datapoints you are after, but that's both really hard to scale and often ends up being highly coupled to the underlying datastore.
I get it, requirements gathering and making a clean API is hard and time consuming. What's harder is not doing that and needing to eventually figure out "How on earth can I get constant response times or stop someone from sending an app crashing query all while supporting current usages".
The former isn't THAT hard to do. The latter is extraordinarily hard.
Get the former wrong and you fix it before it ever goes live. Get the latter wrong and you fix it only after you're massively pwned.
This is just a bad tradeoff.
That's where I've often run into the problem. When someone wants to make a monolith into a more microservice thing the hard part of carving out monolith usages takes meetings with consumers. Devs don't want a bunch of meetings and requirements gathering and a lot (at least in my org... :( ) would rather just write something cool and throw their hands up and say "We don't know how you'd use this, so we made you the boss".
SQL is just a query language, just like GraphQL, and is no less 'secure'. You can still have a layer between the front end and application database.
A practical way to use SQL would be to expose the subset of data that is visible to the user and allow that to be queried by SQL, just like it would be by GraphQL or REST.
It lets us build reports and other configurable data queries in a standard way for our case.
I can completely see how this makes sense using SQL although I think the complexity of the implementation might be a fair bit higher than mingo.
Then I remembered my experience of working with an SQL-like based API, that was a pleasant surprise and joy to work with.
I do not see why we can't use it from a client-side perspective, and safely re-cast it server-side.
It's something you should never do. Off the top of my head:
1) Security (as has been beaten to death here)
2) Interface versioning. If you expose a generalized SQL interface to your consumers directly, good luck ever making a change to your database schema. You'll have no idea whose workflows you break. This high coupling becomes very painful very fast.
3) Abstraction. The way data is stored is often not the way data should be surfaced. What about application layer data integrity, things like that? This would require the frontend client to have far too specialized of knowledge as to how the backend works.
4) Optimization. How do you optimize for queries you don't control? Someone will craft something that can bring your database to its knees under load without even trying to.
You solve a big chunk of your problems that way.
I guess what I would argue against in this post is that SQL is the right language for this. The post starts off with the assertion that we're just using SQL on the backend anyways - not so, in fact my company doesn't have a single SQL database.
But I think the overall point remains - if you want powerful clients you can't beat a query language.
Apache Calcite comes to mind: https://calcite.apache.org/
A tweet storm: https://twitter.com/jlongster/status/1341586372252078083
A blog post which mentions some of how it works: https://actualbudget.com/blog/porting-local-app-web
A more recent tech talk (which I haven't watched): https://blog.fission.codes/building-actual-budget-with-james...
But the idea is directionally correct. Replicate the subset of data the user has access to and wants locally and work on it disconnected, then sync changes asynchronously to server. This is difficult, but necessary for fully responsive and collaborative applications.
Check out https://replicache.dev for a productization of this idea (disclosure: this is my product). We will eventually add a SQL frontend for the cached data.
(We've shipped this now, but not re-announced it yet).
I'd want to call it "SQL Injection as a Service", but is it even injection anymore when the client can just send whatever SQL they want? Trying to filter and validate the SQL on the backend to restrict what a client can do would be an absolute minefield and would be so difficult to get right that you wouldn't save any time.
I also expect fans of Django and the like to be opposed...
frontend sql statement as a json object:
{
select: {
name: field(Project, 'name')
},
from: table(Project),
where: equal(field(Project, 'ownerUsername'), '<my-user-id>'),
}
and here a rule configured on the backend: const rules = [
allow(authorized(), {
select: {
name: field(Project, 'name'),
},
from: table(Project),
where: equal(field(Project, 'ownerUsername'), requestContext().userId),
})
],
Sadly documentation is quite poor for now, but you can check it out here https://github.com/no0dles/daitaEdit: code formatting
That sync protocol could be anything (rest, rpc, graphql, or even xml changesets in zip files on webDAV - I’m looking at you OmniFocus)
This setup has the benefits of being able to work offline (just sync later when network is back) and the ability to perform local SQL queries to populate UI views. But comes with all the extra complexity related to synchronising local and remote database. Stuff like handling conflicts.
The post is here: https://ohdoylerules.com/web/sql-as-an-api/ The code is here: https://gist.github.com/james2doyle/9e4b2b4f17e33bfb236fbdaf...
Also not SQL, IndexedDB [0] Seems like a well-supported [1] document database built into the browser would beat LocalStorage in almost every way. That's what I've found in my experience at least.
Maybe SQL just isn't the right tool on either the frontend or the backend?
[0] https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_A... [1] https://caniuse.com/indexeddb
If you build it upon SQL, you would also need to create a CRDT schema to make replication sound. That's probably more work than just using REST/GraphQL/RPC.
Local data is king. Especially as the network connection degrades.
const users = await sql.query`select * from users`;
console.log(users);
and in production this becomes something like const users = await fetch('/query?id=19a1f14efc0f221d30afcb1e1344bebd');
console.log(users);
and the query itself stays on the server so you don't have to deal with the problem of unbounded complexity / DoS.This is the same approach Facebook uses for GraphQL. The only reason I gave up with this idea is that getting the developer experience right is hard work and it does introduce some very tight coupling!
The article is less about remotely executing SQL, but more about having a relational data model as a cache in the frontend.
However, when sending the query through to the backend on a cache miss, would be useful to only allow queries that have been extracted like so.
Its similar to how Apollo does query [caching][1].
I really like it!
[1]: https://www.apollographql.com/docs/apollo-server/performance...
Legacy codebases are hard to remove because it's difficult but once you turn every SQL call into an HTTP call... the remaining part is the logic which can be rewritten into something more modern.
> I usually end up with a bunch of Lodash (groupBy, filter, map, reduce) to shape the data I get from the server.
I mean, we are also doing the same thing with ORMs on the backend.
I sure do. Nothing beats being able to just copy/paste a SQL query from a code base to your client to see what's going on. Then tweak that said query until it works as expected. When I do backend development involving the database a lot (and I do use a lot of views, functions and triggers), I spend more time in my database client than in my IDE.
It's subjective and I tend to disagree. Especially for very simple and very complex queries.
Also, unless you are a following a "code-first" approach and doing all your schema migrations through the ORM, you have to redefine your tables, columns and relationships a second time and keep them up-to-date with every change, which is a huge hassle.
Obviously if your app is a simple CRUD app, might be simpler to just use Rails/Django/Symfony with an ORM and embrace the code-first approach.
In fact, I'd argue that the "code-first" approach as you call it is actually more useful, because rails gives you bindings for before/after commit hooks, validators that aren't supported by SQL, etc.
> Also, unless you are a following a "code-first" approach and doing all your schema migrations through the ORM
I've literally never heard of a rails team migrating their DBs manually. Everyone uses ActiveRecord because it's a joy to use and very well supported and documented.
Strangely enough, I hardly ever see anyone really use the Postgres security checks. Postgrest is pretty much the only use case I've ever heard of.
I love working with PostGREST and have used it quite often for quick services (e.g. a vote button on a static site), internal tools (recently a covid checkin-screener), and for Proof of Concepts (postgres+postgis-powered full text search for address lookups in a webmap without using an external geocoder).
I personally have yet to use it for something with more than 200 users, but it sounds like others certainly have successfully. Supabase (https://supabase.io/) uses this for parts of their backend.
10 years later, there are special cases on top of the special cases. The reality of compromising over and over when adding new features has added up and it's hard to remember the right way to get the correct currency converted total for an invoice (so you need to get the total in each currency, but not add the line items that are marked as 'deleted', then apply discounts, then convert currencies to USD, then add tax, then add shipping, then convert to the local currency, except when the delivery address is in Russia where legally you have to ...). Lots and lots of things are like this, and with no abstraction to ensure that these computations are isolated in a single component in the system you are going to get nowhere.
I think the read/write-through cache to a backend database is the missing piece...at least as far as I can see.
Combined with row-level permissions (which my library abstracts), I think it's a very powerful and usable approach to apps where storing structured data is the main goal.
Article for an older iteration: https://dvdkon.gitlab.io/mocasys-dascore/
Although not SQL, this is essentially the approach Meteor takes where you have your same DB on the front and back end https://www.meteor.com/
[1]: https://postgrest.org/en/stable/schema_structure.html#schema...
For one, permissions around SQL are already crap. It takes the smallest screwup to expose data in co-mingled databases. No need to make it even worse.
For two, at least if the SQL is on the backend, a fix for an exponential query DDOSing your DB is fairly quick; you don't have to worry about some client keeping a cached copy of the frontend around for months at a time.
Finally, if you let the frontend send SQL, you have lost any and all ability to do a static audit against the queries that will be run against your database - because you have no control over what the client does.
No, they aren’t. At least not Postgres, and AFAIK its true of every other major RDBMS, too.
Non-DB-specialists typical level of knowledge of DB permissions may be, but that’s a whole different problem.
Yes, Row Based Security exists. But not by default. It also requires you to have one database user per external user. Something I (and most InfoSec professionals) wouldn't be keen on automating or managing, for fear of getting it wrong.
[EDIT] The following was removed from the parent post. It was in response to "you can't audit queries".
> No, you don’t
Citation needed. Yelling "No, you don't" without anything else is fscking useless in moving a conversation forward.
If the query is coming from the frontend, it's coming from a client that is outside of your control. I.E. you don't know what queries will come from the frontend, because the user can execute an arbitrary query.
If you take an effort to extract and bake those queries into a backend (perhaps calling it a proxy), then you're not actually emitting SQL from the front end, you're relying on a backend to emit the actual SQL used after performing a number of security checks. AKA, the status quo.
So?
You are adding a database entry per external user, along with data identifying their roles/permissions in the app, one way or the other.
You can either use custom code you’ve built on top of the DB engine to apply this, or you can use the far more battle-tested code in the database engine.
I’m not sure why so many developers believe reinventing the wheel on database security is more effective than understanding their tools.
0 millions for me.
I'll stick with the well tested and explored method of having a users table with foreign keys on the ID to other tables to identify data ownership.
The idea of using one DB user per end user is, at best, novel and untested. We don't know where or how it will fail. Scaling would be a real bear too. And I'm fairly certain an InfoSec professional would have kittens if they saw that attempted in a production environment.
Its a technique older in continuous use with RDBMSs and more battle-tested than, say, the web itself, and plenty of enterprises (even the kind that have apps that not only don’t provided direct DB access to their frontend, but don’t even provide their backend access to tables or views but mediate all external access to the DB through sprocs) have it as a security norm and (correctly) view apps that manage end-user access outside of the database as taking a relatively novel, untested, and risky approach.
For non Kerberos Linux systems using LDAP to synchronize group membership is the only extra automation needed.
It is possible and fairly easy to manage a very large number of accounts IF done properly.
SPARQL is really nice for querying graph data, but I'd argue that for most applications tree-like hierarchies are good enough. Also GraphQL and associated frontend libraries are written to be consumed by browsers and results are much easier to handle than results from a SPARQL query, JSON+LD is not the easiest format to handle. The tooling around SPARQL is not great compared to GraphQL either.
Furthermore I'd argue that SPARQL queries are really hard to statically analyze / optimize on the Backend. Different SPARQL engines behave differently and whether you run your query against e.g. Stardog or Virtuoso can have vast performance differences. SPARQL being hard to analyze statically actually becomes apparent once you start thinking about authorization of resources, it is not a trivial problem to know to which resources a client should have access to or not.
And while it is true that you can model provenance, authorization and all kind of other niceties in SPARQL as well, you will likely be on your own building all those tools yourself.
I believe SPARQL is a great query language for public / open data, e.g. Wiki Data, Government data, etc, but in a business context I'd rather choose REST or GraphQL over it.
The complexity and security costs just keep going up the more logic you shove into an untrusted client.
- super hard to cache if any client can basically generate an infinite number of different queries.
- which dialect of SQL ? If you change DB or upgrade version, do your ask all clients to change as well ?
- how do you do query that involves several data sources ? Some response data come from redis + elastic search + postgres. That's why FB created graphql. That's also why it's so limited in scope, so that complexity is manageable.
- do you want to expose clients to implementation details such as OUTER JOIN vs INNER JOIN vs an array ? Or let them figure out tricky queries involving HAVING, DISTINCT, COUNT or subqueries ?
No, you implement an exposed schema for each app (or possibly more granular) that consists of objects (mostly views, possibly sprocs) optimized for the planned access pattern of the app (or whatever client/component thr schema is for), including convenience views abstracting those things away to the extent appropriate for the use case. That’s been a widely known RDBMS best practice for decades.
Caching: This is true of any API allowing, for example, advanced search. If you can get by without it, great, but it's often a requirement.
Dialect: I don't think it's a terrible idea to bet on one (ideally stable and FLOSS) database, it's just a risk to be managed, and I think it can provide benefits in some cases. Or you could be fancy and use jOOQ's SQL dialect translator (this could also be used to create a "custom dialect" without some features).
Multiple data sources: You could use PostgreSQL's Foreign Data Wrappers. An unorthodox solution, but it allows seamless access with fast joins.
Complex SQL features: I don't think it's really a problem, in complex analytics code I think some users would actually appreciate having all these features. It can be a code quality challenge, but I think that's better solved on a personal level.
This approach does have real problems, like it being hard to prevent DoS attacks, but I don't think there are as many problems as it seems on first glance.
The way I understood the article, the ideas is 'can we expose a safe subset of SQL or fix the security issues instead of continuing to build entirely new systems'
People forget (or don't care) about security or safety when it lets them move faster.
"Move fast and break things," is a terrible security model.
Then I generate my client code from the GraphQL schema. I like strong typing so I use Elm on the front end. Now I have strong typing from SQL table to frontend code.
This is a game changer! I dont even want stringly typed SQL, not in the backend not in the front end. I want strong types guarding me against my own stupidity.
I’ve been using both the past few weeks and have preferred Postgraphile.
- Postgraphile has better Relay support, stuff like returning added edges, returning deleted nodes, good global ID support.
- Hasura didn't support something like adding a currentUser field when using the Relay support. The pagination in the non-Relay mode was very basic and didn't comply with the Relay pagination spec.
- Comparatively even when not using Postgraphile's Relay support it still supports both the Relay pagination API and the easy "nodes" pagination API.
- With Hasura I initially liked the UI for management but found it tedious as I continued working.
- I came across some bugs with Hasura's pagination API's, which was the final thing that made me decide to switch to Postgraphile.[0] https://lambdaforge.io/2021/03/03/datahike-clojurescript.htm... [1] https://github.com/metasoarous/datsync
(This despite the fact that every Linux distro uses the same kernel and Linux hasn't suffered some sort of monoculture meltdown.)
[1] https://nolanlawson.com/2014/04/26/web-sql-database-in-memor...
> We were resolved that using strings representing SQL commands lacked the elegance of a “web native” JavaScript API, and started looking at alternatives.
> In another article, we compare IndexedDB with Web SQL Database, and note that the former provides much syntactic simplicity over the latter.
IndexedDB and "syntactic simplicity". For anyone who has worked with that API, boy oh boy.
[1]: https://hacks.mozilla.org/2010/06/beyond-html5-database-apis...
The front end is an untrusted computing environment and anything you give to your front end developers you also give to potentially hostile users.
The security implications of things like GraphQL are, frankly, bonkers, but nobody seems to notice.
This is in stark contrast with the server side, where you do have a trusted computing environment and you can, to an extent, give your developers what amounts to "root" access to the database.
I wrote a blog post on this a while back:
https://intercoolerjs.org/2016/02/17/api-churn-vs-security.h...
A simple statement like SELECT Age FROM Employee WHERE name = 'Frank' turns into a monstrosity like
POST Employee/_search { "query": { "bool": { "must": [ { "match": { "name": "Frank" } } ] } }, "fields": [ "Age" ] }
Thankfully they added rudimentary SQL support so I could use it in ad-hoc queries.
I have to look into it, but some posters mention blitz.js, this may be just such a thing.
It solves the security issue by making you define the query first in Seamless, and then you get a REST API endpoint to run that query, with optional parameters that are run in a prepared statement.
Query (in the Seamless backend)
> SELECT * FROM posts WHERE author_id = ${author_id} LIMIT 50
And corresponding REST endpoint for that:
> GET https://primary.dbapi.seamless.cloud/somecompany/queries/run...
I dogfooded it while writing the serverless backend for BudgetSheet, and in practice I got tired of having to pre-define each query up front in the app before I could run it from the app. It was kinda painful to switch back and forth vs. just having the queries in the codebase. So... I have definitely been thinking a lot more about how to move the SQL to the client, but in a secure way (perhaps in cobination with the Seamless app that only allows "verified" queries to run in production, etc.) There is definitely some room here for a little innovation.
https://caniuse.com/sql-storage
Supported in Chrome 4, circa January 2010.
I'm forgetting the name of it but there is a spec, I think in wicg, for low-level/byte-level file access. This should make using emscripten to compile things like sqlite far more straightforward, to build whatever you want.
I like the shout out to streaming changes out of the database, which the author mentions in terms of redux & time travel abilities from having a wal. Server side systems like Debezium for doing this have been gamechanging. At the moment, the high-level file api has no support for watching for changes (https://github.com/WICG/file-system-access/issues/72). Maybe post 1.0 we might see progress. I don't believe the low-level api has anything for watching for changes.
From a more meta-assesment level of this article: I do hope we can stick with HTTP centric entities, personally. GraphQL with it's generic endpoint that all operations get sent to is, in my view, quite a bad development. But not irreconcileably so: bridges could be built. I'm definitely in favor of experimentation, trying things out. But I also think there's good reasons to keep entities and their urls around, to not abandon that. GraphQL right now doesn't seem to think about that or care about that, but I also think it could be reformed.
https://softwareengineering.stackexchange.com/questions/2202...
>Byte-level storage
Would be cool.
---
https://hacks.mozilla.org/2010/06/beyond-html5-database-apis...
> From article: we think developer aesthetics are an important consideration...we were resolved that using strings representing SQL commands lacked the elegance of a “web native” JavaScript API, and started looking at alternatives.
Seems a bit short-sighted considering SQL is super popular today on the backend.
So, no thanks.
It doesn't exist yet, but when the tooling is there it's really going to make a splash.
https://github.com/porsager/HashQL-todos-sample/blob/master/...
New FE devs that come in now have a 6 month period where they must learn a new proprietary tech just so that we can circumvent what's already there, I would say that it's not a great idea if you have to work with other FE devs (who are not Full-stack) and if your app is of a significant size (YMMV I guess, we've had our own issues with GraphQL too).
A better solution would be a GraphQL like API that leverages SQL.
It wasn't always clear whether any given piece of processing logic belonged in the frontend or backend code, and trying to manage the contract between the two seemed like unnecessary busywork when there was already a well-designed interface between the backend and the database.
In the end this 3-moving-parts design did work, but I wished I had tried something like AWS AppSync[0] which is basically "managed GraphQL".
Fundamentally SQL the language is not designed for the added complexity and and I'm not aware of anything closer than GraphQL.
There are security, transnational, caching and computational questions to solve.
Edit: Maybe FirebaseDB et al are better analogs, actually.
I've been on the data side for a long time and have always wanted to explore front end but the API mandate sure did make that learning curve difficult, but for good reason.
It would be ideal if someone could iterate the existing frameworks to step something like GraphQL to a full blown front to back SQL tool.
Anyone who says SQL perms are crap doesn't know what they're doing with perms. I agree something is going to have to eloquently add controls between front and back.
Very thoughtful piece.
I personally know how to mitigate the risks better in a middle-tier GraphQL server than in a database, but I'm open to the idea that database security controls might be up to the job, too, if not now, then maybe in the future.
I think there's a lot of naiveté in this post, but I appreciate where the naiveté is taking us.
You can easily hide or rename fields that you don't want exposed, override their behavior in Node, and add generated columns or fancy SQL mutations either in JS or directly in your DB and have them exposed as you'd expect in GQL.
With a commonly-used plugin, you can even do rich ORM-like queries directly from graphql, like:
query {
allPeople(filter: {
firstName: { startsWith:"John" }
}) {
nodes {
firstName
lastName
posts(filter: {
createdAt: { greaterThan: "2016-01-01" }
}) {
nodes {
title
body
}
}
}
}
}
More examples here: https://github.com/graphile-contrib/postgraphile-plugin-conn...(Personally, I think their docs are good at telling you how to use it but fairly bad at showing how great the tool is)
The Apollo cache seems to be powerful enough normalize the way you want, perhaps with some extra code: https://www.apollographql.com/docs/react/caching/cache-confi...
Apollo also claims support for cache persistence, eg to localstorage: https://www.apollographql.com/docs/react/caching/advanced-to...
I haven't used Apollo myself so maybe it's not as usable or powerful as it claims to be.
But the data model of a complex app is usually more than its sql database. So maybe something closer to gql with code gen for your database is more appropriate?
This gives front-end devs the flexibility of GraphQL, composability for free (EQL's DSL is just a data-structure you can manipulate easilty) and is database agnostic.
In fact, Pathom makes it easy to link different datasources and make them available in a uniform way to the front-end devs. All the while, resolvers (running on the backend) keep control and prevent malicious clients from doing harm.
Same issues you would have with GraphQL though: N+1 queries need special consideration when writing resolvers.
Two hours later that dev sent me a screenshot with our competitor’s production catalogue consisting of memes.
I told him to delete them so we could sign the purchase agreement without further ado.
To this day they don‘t know and I sometimes wonder how they ever got so far.
And this, ladies and gentlemen, is why you leave backend query languages to backends and just use GraphQL...
and all the security can of worms. Seriously, if you don't respect the benefit of the text layer in JSON then you need to go have a look at why .NET Remoting failed. You want loose coupling here.
Perhaps I'm missing the point of the article?
* Every user in the web interface gets a sql database user.
* A change in the database schema should reflect an instant change in the AP GUI.
A dream that I have worked towards step by step in a few different projects. I am not sure about how it scales to millions of users. But if you have a a few 100 to a thousand users. It should be fine. Main problem i have found is row level security. The app should basically just be a graphical interface that can be configured. Through a config file.
I don't want to have SQL on the frontend, I want to have no-frontend.
I'm not advocating to the good old days of backend + HTML and full page refresh, a small layer which smartly dynamically load different pages / submit requests would be acceptable.
It was a pretty big pain to write the middle ware necessary to make this happen. So I kind of agree.
Of course it's been tried. It's because it's been tried enough that people now tell you to hide SQL behind a middle layer...
If you want to cut down the overhead, use a simple PHP app and deliver prerendered HTML with JS just for the ajax calls. Its fast, reliable and tested in the wild. Servers are so powerful they can handle thousands of users at the same time.
You also don't drain the users batteries anymore, a win-win.
I'll scream from the rooftops: Yes. Meteor has its shortcomings, MongoDB being a big one, but this pattern of unification is so fantastic for every party involved that even reading about the "new-fangled acronym for building apps" disappoints me.
Now, we've got the JAM Stack (that's the new one, right?): you got your separate web frontend and service-oriented backend, probably communicating over GraphQL, then you've got your database language, probably SQL, but wait, lets put Prisma in front of that so that speaks GraphQL, but it'll be a different GraphQL schema than your frontend because you don't want to expose data, and jeeze maybe serverless functions as well, that sounds good, and i'll just stop typing here because the level of complexity and intricacy we've reached just to build a fully-featured web application is far beyond useful.
The new-generation tools we've built to make development easy for teams of 200 engineers now demand that every team have 200 engineers. Its a self-fulfilling prophecy; congratulations, you just universally raised the cost of software for every human on the planet.
A few days ago, I installed Nextcloud on a little $10/month Digital Ocean instance. I'm blown away by the performance this PHP app puts down. Blown. Away. Using Google Drive, a pretty damn "snappy" app relatively speaking, feels like walking through mud in comparison, and lets not even go down the rabbit hole of the billion dollar data centers and 56 core Xeon Platinum processors behind Google Drive.
Modern web stacks fail along every metric, except "how easy is this for our massive team of developers to maintain." (Of course, they don't actually "fail"; we developers just move the goalposts so 'master' passes, future changes might fail it but we can fix that). They're insane to get started on, hard to maintain, hard to monitor, and at the end of the day have far worse performance for end-users. We started with the monolithic systems which share a ton between server and client, decided those were a mistake, then overindexed in the entire opposite direction instead of iteratively addressing what was wrong with them.
I predict a move back in the opposite direction. The situation has become insane, and I want PHP, Meteor, and Rails. Fortunately, they're all still there, but Meteor has mostly fallen into maintenance mode (not to mention, MongoDB), and JavaScript really doesn't have another solution like this.
The amount of spaghetti react, redux, rxjs, custom form libraries etc is crazy. Validations fail everywhere, what we do in the frontend is inconsistent with what we do in the backend. Many screens have no url so you cannot share them. Despite just being forms it is incredibly slow and feels "heavy". Doing any change takes ages despite all the testing we have in place.
I know things can be done right with the SPA approach, but it takes a ton more effort.
I miss using rails/django, specially when the use case screams for it. But people want to have fun and do what facebook and google do, only problem is we have 0.001% of their resources.
Apollo GraphQL is the same company that brought us Meteor by the way.
If you take a look at what you need to write to get good optimistic UI updates it is crazy compared to what Meteor was.
https://www.apollographql.com/docs/react/performance/optimis...
But as you said, if you need optimistic UI updates and you have 200 engineers you will get it done, but developer efficiency seems to not be popular at the moment.
There is a W3C specification to bring SQL to the browser but it's no longer maintained. Chrome used to support this.
- a sqlite database for each user on the backend
- then on page load, have them download their whole sqlite db on the frontend
- sync the two with something like litestream.io compiled for webassembly
for individual users, this might have a lot more potential.
The advantage of this design is you get an app that is extremely responsive and offline capable. Then you just need a reliable way to sync changes. And you always have the option of just re-downloading the entire team db again if it gets corrupted somehow. You could even have logic to indicate the sync status of each table so that you don't need to download the whole table...you could just populate it as your need the data...like a cache.
Let your backend application worry about the SQL.
Think Flink or Spark or ksqlDB's views server-side, sliced and sent to tables client-side; where other views join these tables and animate React components
This post: treat everything like a SQL database
What's important is that those two EXTREMELY important paradigms of data organization basically don't support each other without kludges galore.
Hierarchical vs relational
But, fundamentally I agree with the poster, what we want are powerful proven data models and powerful proven access languages (SQL for relational, for hierarchical, I'll just throw out XPath which is basically the ONLY good thing from the era of XML that I liked).
Graph could potentially be considered, but IMO it has never proven itself in the practical marketplace. In particular it has no proven and stabilized query language in wide use by people that aren't domain experts, unlike users of the filesystem (basically everyone with a computer) and (less universally) users of databases.
SQL is right there available to me when I'm working on the front end templates.
It's honestly faster to just use that ... often compared to typical API calls.
- no proper way to extract and reuse expressions - parameterizations are basically string concatenations - a lot that I forgot
There are of course also good things about it:
- it's declarative - it's easy to reason about (in its base form, no recursion, etc.) - it's widely used and known
So while GraphQL is something similar, and having solved some of SQL's shortcomings, it's new and has less mindshare. Also, last time I checked, the implementations in various languages (Python even) lagged behind the specification.
I'd say it's a step in the right direction, but tooling has to be improved I guess.
The front-end and back-end data models are vastly different for any non-trivial application.
A lot of the answers here commit the original sin of think SQL = RDBMS.
Expose the sql OF the rdbms is not ideal (security and all that), but none in this world say SQL demand to be the one of the rdbms.
You can create a SQL layer (alike GraphQL) that is "compiled" to calls that MAYBE are translated to a rdbms.
MAYBE.
If GraphQL is ok, sql is too.
And it’s true this works. If you only have to manage a non-shared todo list.
tl;dr: nope.
What you are describing here is an API.