If you know about GraphQL then you must also know that it has something called an, interface description language, or IDL. The specification for this language allows developers to define their data schema in a very succinct way. And many GraphQL services will allow you to specify your schema using this language.
However this is a post about PostgreSQL. This server does not, at present, understand the GraphQL IDL language. It knows about SQL99, plpgsql, and a handful of imperative languages. If you want to define a schema in this server then you already have a language for it.
So why would you ever use PostgreSQL?
Well you have to store your data somewhere. GraphQL is just a query language just like SQL is. PostgreSQL give you more than just SQL though! It’s an application server and it gives you many tools for managing data and building applications.
The important thing to grasp in any good software design is the design of data. In this article I’m going to show you some tricks for managing data design in PostgreSQL that works really well with a GraphQL API.
I’ll also share some lesser-known features of PostgreSQL that make it a great platform for developing applications.
When you first fire up a new PostreSQL database you’re given a few
schemas and not much else. The important one is the
schema. Like any good API design this is where you should expose your
data for your consumer: your web server running your GraphQL endpoint.
The first thing you should do is create a new schema for your
project. Let’s just call ours,
project for lack of a better
name. It’s in this schema that we will define our first schemas. Let’s
start with something simple:
CREATE TABLE project.authors ( id serial primary key, first_name varchar(140) NOT NULL, last_name varchar(140) NOT NULL, birth_date date ); CREATE TABLE project.books ( id serial primary key, title varchar(140) NOT NULL, summary text, author int references authors(id) NOT NULL, published date, unique(title, author) );
In most tutorials and articles on web development you’ve probably come
across some example like this. The difference here is that we’re
creating our tables in the
project schema. We haven’t defined
anything in the public schema yet so let’s do that now:
CREATE VIEW public.authors AS SELECT id, first_name, last_name, birth_date FROM project.authors; CREATE VIEW public.books AS SELECT id, title, summary, author, published FROM project.authors;
What we have done here is abstracted our public view of our library’s
data. We can now add new columns to the
project.authors table, for
example, and not affect our public view of that data. This is perfect
for adding administrative columns to tables and having the view simply
not select them. Now consumers of your public schema will never see
your admin flags or password fields. In fact let’s write an example:
ALTER TABLE project.books ADD COLUMN deleted boolean DEFAULT FALSE;
We’ll use the
deleted flag to allow users to delete books from the
library. However we don’t actually want to delete the row right away
for reasons. So instead we write a trigger function and add a
trigger to our view:
CREATE OR REPLACE FUNCTION soft_delete_book() RETURNS TRIGGER AS $$ BEGIN IF TG_OP = 'DELETE' THEN UPDATE project.books SET deleted = true WHERE id = OLD.id; RETURN IF; RETURN NEW; END; $$ LANGUAGE plpgsql CREATE TRIGGER replace_delete_books INSTEAD OF DELETE ON public.books FOR EACH ROW EXECUTE PROCEDURE soft_delete_book();
What have we done here? We’ve allowed the consumers of our public
schema to delete rows from our
books view. To the users of our
GraphQL API this will effectively appear like they just deleted their
book record. However we replaced the delete action on our view with
our own function which sets the
deleted flag on our internal table
This has plenty of other benefits. Priveleged users could be given
access to see deleted books. We could allow users to undo a mistaken
deletion. We can grant limited privileges to views in our public
schema. We can add new columns or even tables and start building out
the public interface to
books by adding more, rich data without
having to modify any of our API code.
Why is this great for a GraphQL endpoint in particular? It gives you control to evolve and develop your schema behind the scenes. You can add feature flags without updating your GraphQL server or accidentally exposing them to your users. As well you continue to benefit from that relational goodness where you need it: foreign key constraints, some of the best index types on offer, and the rest of the PostgreSQL eco-system to boot.
Which brings me to…
It’s these sorts of features that make PostgreSQL my go-to choice for building enterprise and web-services based applications. When people think of an RDBMS I think they mostly see SQL and tables. But there’s so much more than that in PostgreSQL.
One of my recent favourite features is
pg_notify. This handy little
function allows you to integrate an external process with your
database and notify it of various events in the server. For example
perhaps we want to send an email out a thank you email to someone who
just created a purchase order:
CREATE OR REPLACE FUNCTION update_notify() RETURNS TRIGGER AS $$ BODY IF NEW.success = true THEN PERFORM pg_notify('purchase_order_successes', json_build_object( 'id', NEW.id, 'username', NEW.username, 'email_to', NEW.email )); END IF; RETURN NEW; END; $$ CREATE TRIGGER notify_purchase_order_success AFTER INSERT OR UPDATE ON purchase_orders FOR EACH ROW EXECUTE PROCEDURE update_notify();
Here we’re using PostgreSQL’s
pg_notify function to send a message,
encoded as JSON, to an external process after every insert or update
purchase_orders table. This process can use that data to
perform the task of sending out our email.
Of course there’s more you can do with this feature but did you know that PostgreSQL has foreign data wrappers? An HTTP client?
There are an immense number of tools in the PostgreSQL toolkit that make it such a great companion to a GraphQL endpoint. That’s why I started postgra.ph. I love PostgreSQL and I love GraphQL. When you put them together you can finally rapidly develop APIs that will integrate well with your existing ecosystem and scale as your application grows.
If you’re interested in a low-touch, managed PostgreSQL+GraphQL solution for your next project click the link to my project and leave your email. I promise not to spam you! The list will simply notify you when I’ve launched the project so that you can get involved in its development early.