12 ms·
The API database architecture – Stop writing HTTP-GET endpoints
- wrs 2y agoWell, the key thing here is writing SQL views to do the access. Once you’re willing to do that, it’s a fairly minor distinction between using PostgREST or writing a thin, possibly even generated, API layer. But that’s exactly what people are typically not willing to do.
- gregw2 2y ago100% agree. And once you are writing SQL views, why use PostgREST and not just use your own framework which abstracts away your choice of Postgres as backend database with something more database agnostic that can point to a view in any database technology? Isn't a main part of the value of an API layer to decouple you from a particular database implementation? If so, why use PostgREST?
- anamexis 2y ago> Isn't a main part of the value of an API layer to decouple you from a particular database implementation? I think the value of an API layer is to provide an interface to interact with, which is a) at the right level of abstraction for the task at hand, and b) in a format that is easy to use.
- dventimi 2y ago> why use PostgREST and not just use your own framework which abstracts away your choice of Postgres as backend database with something more database agnostic Because I'm sticking with PostgreSQL and don't need database agnosticism, and because I don't want to write my own framework when a better one already exists?
- martinbaun 2y agoVery interesting, I knew about PostRest, but never checked it out. A lot of the boilerplate can probably be cut away with using PostRest. Just wondering, what about security and especially if someone decides to DDOS your server with high-load queries? Do you try to filter/block those with NGINX?
- eyko 2y agoSpeaking of postgrest, it looks like the article links to `www.postgrest.org` which has been "hijacked"? The correct url should be https://postgrest.org https://postgrest.org
- dewey 2y agoHijacked seems like a strong word for a 404 page. I was expecting a crypto scam or gift voucher directory.
- dewey 2y agoI don't understand what's the benefit of adding additional third party code into the hot-path. Adding yet another endpoint is hardly a lot of work, sometimes even auto-generated and has the benefit of being available in your existing monitoring / instrumentation environment already. Also what about caching if people can "craft" random queries and send them straight to your PG instance?
- nicholasjarnold 2y agoAgree. I've always thought that PostgREST is an interesting project for some niche use-cases and teams. However, his argument about replacing GET request handling with a new tool that lives outside of/alongside your existing application architecture is not a particularly compelling argument. With properly-factored application code adding a GET (list) or GET-by-id is fairly trivial. The only complexity I've ever run into there is implementing a pagination scheme that is not the typical "OOTB framework" limit/offset mechanism. I still don't think this makes the argument much stronger.
- dventimi 2y ago> a new tool that lives outside of/alongside your existing application architecture It need not live either outside of or alongside application code. Substituting application code with PostgREST is an option. > With properly-factored application code adding a GET (list) or GET-by-id is fairly trivial. If it's trivial then it sounds like needless busywork to me. I'd rather generate it or have ChatGPT write it than pay a developer to write it, if it's being forced on me. I'd rather dispense with it altogether if I'm allowed.
- nijave 2y agoHaven't used postgREST but similar tools and these can useful for small/internal apps where you have trusted users
- dventimi 2y ago> I don't understand what's the benefit of adding additional third party code into the hot-path PostgREST doesn't add an additional third-party library. It replaces one or more third-party libraries: Spring, Django, RoR, etc. > Also what about caching if people can "craft" random queries and send them straight to your PG instance? Put the SQL that you would've put into your controller code into SQL functions, expose only those through PostgREST, and call it a day.
- schindlabua 2y agoI'm not a big boy architect and I write small software. To me it seems like "modifying microservices" usually want to read from the database aswell and when I have all my DTOs in place and everything I might aswell implement a GET endpoint? Is this just for performance considerations? When you have lots of reads and maybe few writes so you need an extra service to handle the load? Can someone give a practical example?
- fzeindl 2y agoThe GET-endpoints by postgREST are very flexible and support limiting, pagination, ordering, selection of fields etc., which typical hand-written APIs do not support.
- esafak 2y agoThe title does not reveal that the suggestion applies only to Postgres. It is a bad idea to tie your architecture to a specific technology.
- paulddraper 2y agoJust as you can write an HTTP server in many languages, you can write an HTTP server on many databases. PostgREST, Oracle APEX, MySQL Reson. PostgreSQL being the most popular among developers who choose this approach.
- deathanatos 2y ago> The title does not reveal that the suggestion applies only to Postgres. I don't think the OP intends the suggestion to apply only to Postgres: > The name-giving PostgreSQL database is often already available and in systems where it is not, *it can be easily introduced with minimal effort.* … i.e., don't have PG? Not a problem, just introduce it into your architecture! (/s, from me, but I think the OP is serious.) > It is a bad idea to tie your architecture to a specific technology. But I agree. These sort of "just keep wiring boxes together until it works" architectures cause so many headaches IME; so many pieces, each with its own failure modes and bugs. This is where I find the claim the OP makes, > [this design, with PostgREST] is more flexible than one that is developed manually. … dubious. No, the advantage of doing it in code I control is that I control t hat code, and if something needs to change, it can be. With wired-together-boxes-of-random-tooling like this, I have to pray my change fits into the whims of its config files.
- fzeindl 2y ago> … i.e., don't have PG? Not a problem, just introduce it into your architecture! (/s, from me, but I think the OP is serious.) I do think this is fairly simply for many companies. > But I agree. These sort of "just keep wiring boxes together until it works" architectures cause so many headaches IME; so many pieces, each with its own failure modes and bugs. This is where I find the claim the OP makes, I agree, but PostgREST is a very very simple box... > With wired-together-boxes-of-random-tooling like this, I have to pray my change fits into the whims of its config files. ... that needs almost no configuration except the database connection string.
- languagehacker 2y agoThis doesn't seem like a good idea when it comes to consistently hardening an access layer. You mean I get to double the ops maintenance cost of my existing service by adding a new one? You mean I need to figure out how to set up RBAC, rate limiting, logging, and error handling in two places instead of just one? By and large, opinions in API design has suggest against directly mirroring table structure for quite some time. The reasons are many, but they include things like migrating data sources, avoiding tight coupling with the database schema, and maintaining ultimate control over what the payload looks like at the API layer. Just in case you want to do something dynamic, or hydrate data from a secondary service. And if you still want to generate you response payloads like they came straight from the database, there are plenty of code generation or metaprogramming solutions that make providing access via an existing API layer quite simple. This solution seems simpler only because it ignores the problems of most practical service-oriented API architectures. If end users need a direct line to the database, then get your RBAC nailed down and open the DB's port up to the end user.
- delusional 2y ago> If end users need a direct line to the database, then get your RBAC nailed down and open the DB's port up to the end user. I'd really consider creating a new table just for this "database interface" That'll let you keep evolving your internal architecture while preserving backwards compatibility for the client. That won't work in all cases obviously, but I think it's suitable for most of the "sensible" ones.
- everforward 2y agoI thought the prevailing advice was to expose views (materialized or not) rather than tables directly, but I could be wrong or outdated. I still probably wouldn’t do it, though. My “lazy” solution is usually OpenAPI code generation so I basically only have to fill in the SQL queries. Not having any code gives me the nagging feeling that very soon I will hit a problem that’s trivial to fix in code but impossible or very stupid to do via a SQL query.
- dventimi 2y ago
- CafeRacer 2y agoIn reality postgREST sucks... it's fine for simple apps, but for something bigger its pain in the butt. * there is no column level security – e.g. I want to show payment_total to admin, but not to user (granted a feature for postgres likely). * with the above, you need to create separate views for each role or maintain complex functions that either render a column or return nothing. * then when you update views, you need to write sql... and you can't just write SQL, restart server and see it applied. You need to execute that SQL, meaning you probably need a migration file for prod system. * with each new migration it's very easy to loose context of what's going on and who changed what. * me and my colleague been making changes to the same view and we would override changes from each other, because our changes would get lost in migration history – again it's not one file which we can edit. * writing functions in PlSQL is plain ass, testing them is even harder. I wish there would be some tool w/ DDL that you can use to define schemas, functions and views which would automatically sync changes to staging environment and then properly these changes on production. Like when you can have a flask kind of app build in whatever metalanguage w/ ability to easily write tests, then and only then postgREST would be useful for large-scale systems. For us, it's just easier to build factories that generate collection/item endpoints w/ a small config change.
- lishzen 2y agoWe solved some of this by having a "src" folder with subfolders: "functions", "triggers" and "views". Then a update-src.sql script that drops all of those and recreates them from source files. This way we can track history with git and ensure a database has the latest version of them by running the script and tests (using pgtap and pg_prove).
- dragonwriter 2y ago> there is no column level security – e.g. I want to show payment_total to admin, but not to user (granted a feature for postgres likely). Its a feature postgres has. GRANT SELECT ON public_table TO webuser; REVOKE SELECT ON public_table (payment_total) FROM webuser; Not sure why you think it doesn't exist or doesn't work with PostgREST.
- 2y ago
- mannyv 2y agoYeah, let's put another server that can fail in the path of your product because more failure points are better. But at least you're not providing your user a direct link to your database, which is almost always a bad idea.
- dventimi 2y agoIt's not another server. It's a replacement server. It replaces bespoke code that a developer was going to write. Hand built servers can fail too, you know.
- rblatz 2y agoYet another solution that makes easy things easier, while making just about everything else significantly harder if not impossible. RBAC, monitoring, telemetry, merging data from multiple sources, migrating between data stores, database structure optimizations, caching... These are just of the top of my head of issues that this is likely to make harder, all to prevent writing some of the most simple code you can write.
- lyu07282 2y agoperhaps its because ORMs are considered bad by some people, so to them writing these GET API endpoints is very tiresome, having to always construct these complex filter queries by hand. From that vantage point it would make sense to move toward runtime database introspection, but then they realize that the API data model is different from the data layer so they introduce table views, and then they realize their permission system doesn't quite fit into this so they introduce row-level security, ... I don't know why they want to write SQL so much, its a 50 year old language, it sucks ass :P
- dventimi 2y agoPostgREST is not an ORM. I suspect you know that, but others might be confused so I wanted to point this out.
- RedShift1 2y agoIt's like there's a massive army of developers solely focused on writing GET APIs even though we have the tools to completely automate this and more but they always find excuses to not use these tools - this thread is full of them. I don't get it, what they're really doing is just translating a to b over and over again. "Same but different". That's really the last thing I want to spend my time on.
- dventimi 2y ago> even though we have the tools to completely automate this PostgREST is literally a tool to automate this.
- T3RMINATED 2y ago[dead]
- dicytea 2y agohttps://www.postgrest.org https://www.postgrest.org links me to a weird and broken WordPress news site. https://postgrest.org https://postgrest.org on the other hand links me to the correct documentation site for PostgREST. Anyone else having the same problem?
- steve-chavez 2y agoYes, sorry about that. We're looking at it on https://github.com/PostgREST/postgrest/issues/3503 https://github.com/PostgREST/postgrest/issues/3503.
- conqrr 2y agoDepends on who is consuming your API. Are they internal, maybe ok. Anything else, you likely need a transformation layer and also take into account Auth, rate limiting etc. PostgREST sounds like giving read only access to your DB and I doubt it would be as customizable.
- tuetuopay 2y agoOh great, now you exposed your database schema to outside consumers. Guess you're not making any migration then :)
- jonathanlydall 2y agoI’m mostly with you here, but to be fair to the OP, he does suggest exposing database views which does give a certain amount of decoupling from the schema of your tables.
- dventimi 2y agoSpeak for yourself. Personally, I've only exposed views and procedures.
- fzeindl 2y agoYou can absolutely have versioned views that you expose. An URL like /api/v1/customers could be rewritten to /views/v1_customers. That way you can change your schema internally.
- darig 2y ago[dead]
- lyu07282 2y agoWell, database introspection isn't new, we could've done that decades ago, but there are good reasons for the layer of abstraction. Also if you go down this route, I think Postgraphile is a much better realization of that idea (uses GraphQL, not REST): https://www.graphile.org/postgraphile/ https://www.graphile.org/postgraphile/
- dventimi 2y agoI see no particular reason to believe that Postgraphile, while a good tool, is any better (or any worse) than PostgREST, just as I see no reason to believe GraphQL is better than REST. As for layers of abstraction, one can have layers of abstraction with PostgREST: views and procedures.
- lyu07282 2y agoIt's not better because it's gql, it's better because it's more feature complete (like RLS), offers more/easier customization, isn't written in Haskell, etc., but ofc your milage may vary. > As for layers of abstraction, one can have layers of abstraction with PostgREST: views and procedures. I can't even imagine a more closely coupled and leaky abstraction than views and procedures in a database
- dventimi 2y agoThe database has RLS, and I don't care what PostgREST and Postgraphile are implemented in, so personally I'm unmoved by these two claims. As for things we're unable to imagine, what I can't imagine is how table structure (for example) could possibly leak through a view or procedure. You're welcome to try to explain it, though you're not obliged to.
- fzeindl 2y agoThanks for your comment, I will look into postgraphile.
- koromak 2y agoWhen is an app ever this simple? 95% of the time, you're transforming or combining data in the backend, between the client and the DB. Tables are never so pristine.
- dventimi 2y agoSQL is pretty good at transforming data.
- tarasglek 2y agoCan you please add rss to your blog?
- fzeindl 2y agoI will at some point.
- jurschreuder 2y agoThe GET ones are actually easiest to write, like 30 seconds or something.
- xwowsersx 2y ago> Data retrieval generally does not require any custom business logic, while data-modifying requests do This just doesn't seem to be the case in my experience, at least not in most cases. Perhaps for internal services which are completely locked down and you can freely just expose the data via a REST API, but for public facing services I just haven't found this to be the case in practice, except in extremely limited circumstances.
- danpalmer 2y agoYeah this is it. It's all fine until a product manager asks for analytics on this via their analytics tool of choice, and you have to say "sorry can't do that", or you have to build a complex data pipeline all because you can't do an HTTP POST to an external service. Also database migrations are notoriously hard to get right, at scale of traffic, at scale of development pace, at scale of team, and often require a bunch of tooling. This pattern pushes even more into database transactions. I'd rather take a boring ORM plus web framework, where you need a little boilerplate, but you get a stateless handler in Python/whatever to handle this. So much more flexibility for very little extra cost.
- dventimi 2y agoI don't see what the problem is with producing analytics. As for data database migrations, if anything about them is "notoriously hard" it isn't changing views and procedures.
- danpalmer 2y agoAnalytics would need to be written to a table, then you'd need a batch job to come along and read them out and send them into the analytics system of choice in the company. Now you've got extra database load, write load, you can't do it on a read replica but it needs to be on the database primary, rolling back a transaction now has bigger implications than a read-only process, and you're hosting another job to post to the analytics system. I'm assuming external analytics here because almost every product team I've seen wants them. As for database migrations, views and procedures are easier than data migrations, sure, but I've not seen anything around progressive rollout, canarying, etc. Do you do that separately on different replicas? All of these things are kind of solved problems in basic web apps, but all of these would require a bunch of "odd" stuff to make it work hosting in a database. Is any one part bad? Not necessarily, but I generally like to minimise things I have to apologise to new starters for, and this would cause many of those sorts of conversations.
- _AzMoo 2y agoCoupling your API to your database schema is a bad idea. Once you have clients consuming that API you can no longer make changes to your database schema without also updating all of those clients and coordinating their deployments. Advice like this reads like it's coming from somebody that's never stayed in a role long enough to deal with the consequences of their actions.
- simonw 2y agoYou can work around this with SQL views. Design your externally facing API using views that expose a subset of your overall schema. If you need to change that schema you can update the views to keep them working.
- est 2y ago> you can no longer make changes to your database schema without also updating all of those clients and that was a solved problem from 90s C/S architecture, it's called views. https://www.postgresql.org/docs/current/tutorial-views.html https://www.postgresql.org/docs/current/tutorial-views.html Today's B/S shit was a painful and slow reinvention of old things.
- deleted 2y ago[deleted]
- fzeindl 2y ago> Coupling your API to your database schema is a bad idea. Once you have clients consuming that API you can no longer make changes to your database schema without also updating all of those clients and coordinating their deployments. This is not correct. Whenever you need to change an API you need to upgrade your clients or you add a new version of the API. With PostgREST the versions of the API are served as views or functions that internally map to internal tables. It is absolutely possible to change the tables without changing the API.
- sufehmi 2y agoNote: Exposing your database directly to the Internet / external access should always be considered a bad idea & and as a last resort.
- dventimi 2y agoI have noted your opinion and have disregarded it.
- SJC_Hacker 2y agoDon't see any support for CTEs, window functions or joins. Admittedly joins should probably be handled as views, but window functions and CTEs can be very useful in some circumstances. It does seem like for basic CRUD this should be all you need. But you will probably run into situations where it can't handle something, and then you have to write your own endpoints anyway. Writing your own endpoints also allows more flexibility if yu want to do some post/pre-processing steps.
- fzeindl 2y ago> Don't see any support for CTEs, window functions or joins. Admittedly joins should probably be handled as views, but window functions and CTEs can be very useful in some circumstances. They can be used in a view that is then exposed. Parameterized functions for more complex queries can also be exposed.
- dventimi 2y agoJoins are supported: https://postgrest.org/en/v12/references/api/resource_embedding.html#foreign-key-joins https://postgrest.org/en/v12/references/api/resource_embeddi...
- tills13 2y agoOh this is an ad
- graphememes 2y agothis is such a bad idea, ya lets just increase our infrastructure burden 5x to not write 3 get requests
- dventimi 2y agoNothing about this imposes an infrastructure burden.
- socketcluster 2y agoIt's interesting reading this because I implemented a Node.js solution for this problem years ago but it fell on deaf ears. GraphQL was getting all the attention at the time. https://github.com/socketcluster/ag-crud-rethink https://github.com/socketcluster/ag-crud-rethink I wrote it for RethinkDB but it could be adapted to any database as it doesn't rely on changefeeds. I then ended up building a complete serverless solution around it: https://saasufy.com/ https://saasufy.com/ It borrows many concepts from REST but works over WebSockets. Why WebSockets? Two major reasons: - It had to support real time subscriptions/updates so that the views could automatically update themselves when data changed (e.g. with concurrent users). I didn't want to force the developer to manage channels manually as it can be a major headache to get the subscription order right and to recover from disconnections without possibility of missing any update messages. Also, my library SocketCluster already supported client side pub/sub with clustering/sharding on the back end so I wanted to leverage that mechanism. - WebSocket frames are tiny and don't have all the overhead of HTTP requests so it's possible to have field-level granularity which is important for avoiding resource update conflicts. This is something that the GraphQL developers also figured out at some point. But the challenge with true end-to-end field-level granularity is that loading a single resource would require a potentially large number of requests to be made; hence HTTP requests are not suitable for this (imagine HTTP headers containing cookies being sent for every single field of a resource), however, WebSocket frames are ideal for that as they have tiny headers. You can handle maybe 100 WebSocket frames for the same cost as a single HTTP request. End-to-end, field-level granularity is powerful as it allows subscriptions to be set up automatically per-field and access control can be enforced automatically at both the resource and field level (for each of create, read, update, delete and subscribe operations). It's also very useful for caching because different views may display different fields of the same resources with some shared fields so caching field values allows different views to share cache. The overarching philosophy behind end-to-end field-level granularity is that it allows the system to treat each field of a resource as an independent entity with its own subscription/synching mechanism, access control and cache. SocketCluster was designed to facilitate extremely cheap pub/sub channel creation (both in terms of CPU and memory) and automatic cleanup so it seemed like a good use case to build on top of my existing work. The code of ag-crud-rethink is quite simple... Only about 1.5k lines of code and probably could have been a lot smaller without all the bells and whistles. The view mechanism also supports real time updates. It can be thought of as a parameterized collection. You define a 'view' with one or more parameters to control the filtering and/or sorting (though you can construct essentially any query on the back end). The idea is that the parameters for the view are provided by the client. This means that you can represent any view of a collection as a simple string which can be used as a channel name; this is useful for efficiently delivering real time updates since we only want to deliver resource change notifications to views which include that resource. During writes, field names can be cheaply matched against view parameters to decide which instances of the views need to receive the notification. Only clients which are looking at an affected view right now will receive the notification.
- DeathArrow 2y agoI am not convinced. In an endpoint I can do much more than just interrogating the database. And I usually do. It might work for simple cases, but then why not also provide POST, PUT, DELETE, PATCH?
- dventimi 2y ago> in an endpoint I can do much more than just interrogating the database. And I usually do. Like what?
- Alifatisk 2y agoIn my case, it wpuld be to execute business logic, like complex calculations, validations, or workflows that go beyond simple database operations. Another case is integrating external services through API calls, interact with other systems or services to fetch or send data. Format and transform data to prepare data for presentation in JSON before sending it back to the client.
- dventimi 2y agoThanks! I ask because I tend to put business logic into a few broad categories: input validation, data transformation, sequencing, integration. The database can usually handle the first three out of these four well. That tracks with your "complex calculations, validations, or workflows" as well as "format and transform to prepare data for presentation in JSON." PostgreSQL is as good as or better at these tasks than any general-purpose programming language, in my view. Where it gets tricky is with "interact with other systems or services to fetch or send data." While I personally would be cautious about this for purely architectural reasons that go well beyond how it's implemented, "the customer is always right." If I were consulting for a customer who wanted to integrate with external systems, I do have a few tricks up my sleeve. What I hope you'll take away from this is that "business logic" isn't the show-stopper that people tend to think it is when considering building applications in the database. Pretty much all of it can be done. Some kinds of business logic can be handled quite naturally. Other kinds perhaps less so, but it can be done. People may still choose not to do so for various reasons, and that's fine, but there usually aren't technical barriers to putting business logic in the database.
- vbilopav 2y agoHere's an alternative I've built for myself https://github.com/vb-consulting/NpgsqlRest https://github.com/vb-consulting/NpgsqlRest
- fire_lake 2y agoHow can you apply permissions logic that is not easily expressed in Postgres itself? That’s the main reason I want to build an API in a “proper” programming language. I suppose I could build that in front of Postgrest but why add latency?
- SahAssar 2y agoWhat permissions logic is not easily expressed in your database?
- khana 2y ago[dead]
- hervem 2y ago> I call this approach the "API database architecture" Why people can't search for an existing term before creating a new one, it just add confusion into bucket which already contains "DB as API", "DB over API", "DB 2 API", "DB 2 REST", "DB low-code API"
- javcasas 2y agoI have a mixed real-world experience with PostgREST's friend: Postgraphile (I/E like PostgREST but generate GraphQL instead of REST). It's great, but some tools are a bit rough, and people hate you for forcing them to write 8 lines of SQL. The great: authentication works (both internal and using an external service like Okta), most (if not all) standard operations work: get, post, put, patch, delete, filter, sort, select specific columns, autogenerated doc. You have better RBAC than most (if not all) web frameworks out there. The good: proper transactions everywhere, especially if you use a database-backed queue. Use can use views to evolve your interface independent of your data. You keep data consistency at all times. The bad: PostgreSQL permissions can be hard, especially the permissions of views that expose underlying data, and around different schemas. Triggers can get complicated. You need a good tool to evolve your data, and most likely a different tool to evolve your views/stored procs, because they change way more often and for different reasons. The horrible: people. They see SQL and they hate it. They rush to replace 8 lines of SQL with 300 lines of ORM and call it an improvent because there is no longer SQL. "Remove SQL" becomes an objective. It doesn't matter if they replace it with plague-induced gonorreic syphillis, they think it's better. They see a trigger that inserts into a SQL-based queue, now they try to introduce a redis queue, backed by nothing (not even writing to disk), and three endpoints and functions to create and manage it. They claim it to be better, even now that the three functions are unrelated and harder to track. So well, would I do it for my personal projects? Totally. Would I do it in an enterprise project? Nah, they don't deserve such an improvement. Let them have their millions of lines of code to replace thousands of SQL.
- rjst01 2y agoMeasured by LOC, a lot of code in systems i've worked on is just copying data from one type of object to another. One frustrating bug I've dealt with was due to someone copying the wrong value between two similarly-named fields, but the request went through so many layers of the system before it was processed by the buggy code that it took hours to track down. I've spent a lot of time thinking about how to write less of this code, and I think what I want is something similar to Postgrest, but with a mechanism for some sort of hook, where I can write some code to manipulate the request/data in a type-safe way. The closest I've seen to this was early in my career - one of my first jobs was working at a WebObjects consultancy. Because WebObjects provided the full stack from HTML templating engine to ORM - and by that time also community-driven frontend libraries - you had to write very little of this type of code. I suspect also that some of the resistance to the Postgrest-style approach in enterprise environments comes from tighter controls around data, and requirements/expectations for stricter change control around databases. Buggy code can always be rolled back, but a botched database change could be a much bigger problem. (Of course, the fact that buggy code could corrupt or delete data almost as easily is ignored in this calculation). I still remember weeks of meetings at one employer trying to get a column added with the ultimate answer being 'no'.
- joshstrange 2y agoI have seen and tried enough tools like this to know I should run in the other direction. For rapid prototyping this might be acceptable, as long as you plan to replace every endpoint before launch or maybe for a fully internal tool it would be ok. Security is the problem and no, I don’t want to create a bunch of views to attempt to get it right. Different users have different sets of permissions that give them access to different parts of the data in different contexts. You will pull every one of your hairs out trying to make that work with something like this. I’m not trying to be mean but I find things like this or even Firebase-style tools to be massive foot-guns. Sure, if you get the permissions/visibility perfect it might work for you (at this point in time, good luck as you modify it over time) but why take that risk? It’s not like CRUD endpoints are hard to write and I greatly prefer having full control over what I allow in and out of my system in code. That lets me keep all my auth/visibility rules in one place instead of spreading them out over multiple systems, which again is foot-gun. I find “I want a tool that does everything for me”-type thinking and “look, it’s magic and it just works”-type tools to be something junior devs flock to (myself included years ago) before realizing they have given up all the control for something that’s really not that hard to do yourself. Same arguments for if you like key-value/document-based data stores because there is no schema. There are valid reasons to use both types of data store but if you reason is “this way I can easily change my schema” then I question your ability to write stable systems.
- dventimi 2y ago> I don’t want to create a bunch of views to attempt to get it right Then don't. > You will pull every one of your hairs out trying to make that work with something like this No. I won't. I've already made this work, several times. > It’s not like CRUD endpoints are hard to write Then why write them? I prefer to automate that part, freeing me up to solve harder problems. > That lets me keep all my auth/visibility rules in one place instead of spreading them out over multiple systems My auth/visibility rules are all in one place, in one system: the database. > I find “I want a tool that does everything for me”-type thinking and “look, it’s magic and it just works”-type tools to be something junior devs I don't know who you're quoting. I'm not aware of anybody claiming that PostgREST does everything or is magic.
- dventimi 2y agoThe particular tool Fabien recommends may be "PostgREST", but the general approach is "API database architecture", which has been adopted by a number of other tools as well: PostGraphile, Prisma, and Hasura come to mind. There is a lot of criticism of this approach in the comments here, but they exhibit a lot of repetition, so let me consolidate them--along with my responses--in one place and be done with it. You should never expose your database. Let me stop you right there. Please don't tell me what I should do, especially if you don't know what my circumstances are. You'll get a less frosty response if you make your criticism impersonal and frame it in terms of trade-offs. Fine. 'One' should never expose their database. Unless it's accompanied by reasoning and evidence, I'm going to regard criticisms like these as received wisdom. OK. One should never expose their database because of security concerns. PostgREST (for instance) addresses these concerns through a combination of web tokens, database roles, database permissions, and row level security. Other tools (Hasura, PostGraphile) are similar. If this strategy is inadequate, well that's an interesting topic. Please elaborate. If there's valid criticism, perhaps there's something the PostgREST team can do about it. Also, one should never expose their database because the API should be decoupled from the data model. Again with the received wisdom. Fine. The API should be decoupled from the data model because of good reasons, like freeing the underlying data model to change without breaking clients. With this approach, the API can be decoupled from the data model by using schema, views, and procedures in SQL. If that's inadequate, again that's an interesting topic. Let's hear more. If the database is going to be exposed, then just go all the way and open up the database port. Remember the thing above about "circumstances"? Sometimes, the circumstances don't allow this. For example, sometimes circumstances demand an HTTP API. That's going to be difficult for many databases without a little help. That's where things like PostgREST comes in. This approach doesn't save much effort because creating APIs in code is so trivial that it can even be automated. If it's trivial, then why pay an expensive developer to do it? If it can be automated, well that's what exactly what PostgREST is doing: automating APIs. This approach adds another layer No, this approach replaces one kind of layer with a different kind of layer. It replaces (for example) Spring Boot with PostgREST. If Hibernate is also being used, then arguably PostgREST is replacing two layers. ORMs are bad I'm sympathetic to that point-of-view but regard it as a non-sequitur since PostgREST isn't an ORM. Neither is Prisma, for that matter, despite what their marketing material says. REST is bad Traditionally, APIs of any stripe were difficult to code by hand. Web APIs tended to be REST APIs for a long time. Ergo, REST APIs were difficult to code by hand, not because they were REST but just because that was the nature of things. Consequently, REST APIs got a bit of a bad rap. The ease of providing REST APIs with PostgREST, however, warrants revisiting that criticism "REST is bad." But this leaves me no place to put my business logic Well, some kinds of business logic (input validation, sequencing, and data transformations) can be handled in the database. Other kinds are more challenging (side-effects, for example). I'd love to hear the details. Even if the general approach of "API database architecture" can be good, why use PostgREST instead of writing your own framework which is more database-agnostic Two reasons: One, I don't want to write the code and the PostgREST developers are probably better than I am anyway. Two, I don't need the database agnosticism. People who do need support for another database might consider Prisma or Hasura. If that doesn't fit the bill then yes, in that case custom code probably is in order. Building applications in the database, in SQL, feels awkward. Many things feel awkward at first. Building applications in the database just isn't how it's done at my organization. Fair enough, but that's a social obstacle to this approach, not a technical obstacle.