PostgREST Design Philosophy

Preview:

Citation preview

Design Philosophy

goal: Schema → API

Can we use the declarative information in a

relational db schema to mechanically generate

an HTTP API?

Tables/views → Routes

Always one level deep

WHERE clause → query params

Just simple operators like less, greater,

equality, inequality

Provide more complicated logic as views

Primary key → eq: param(s)

A primary key identifies at most a single row

They can be compound and/or natural

Routes like /foo/1 don’t always suffice

/foo?k1=eq.v1&k2=eq.v2

For instance,

if an employee belongs to a dept

Link: <http://me.com/dept?id=eq:7>; rel="dept"

Foreign keys → header links

Limit, offset → Range headers

HTTP/1.1 206 Partial Content

Accept-Ranges: items

Content-Range: 0-24/100

Range-Unit: items

RFC7233

GET /items HTTP/1.1

Range-Unit: items

Range: 0-24

SQL update → HTTP patch

PATCH /people?age=lt.12

{ "type": "child" }

Updates all the matching ones

SQL insert → HTTP post

POST /items

PUT /items?pk=eq.val

with all fields specified in body

SQL upsert → HTTP put

schema search path → API Version

Use numerical schema names in the db

Set schema search path to mask endpoints and

fall through when desired

GET /foo HTTP/1.1

Accept: application/vnd.me.com+format; version=n

DB Roles → OAuth

Web server authenticates you

then connects as your user to db

DB authorizes your (hence server) actions

Column constraints → OPTIONS

We can pipe the options output into a client

side “Faker” to mock server responses for the

client test suite.

PG stats collector → cache headers

The access and modification patterns in a table

can provide a heuristic for http caching headers

Perhaps a special view could allow overriding

etags, max-age, etc for each table via a sql

expression

EXPLAIN → HTTP 413

The server can examine the query plan and

preemptively forbid inefficient requests

Like large seq scans or nested join loops

Deployment is easy

For instance on Heroku create a buildpack that

installs the server binary

Then push new migrations and run them. The

only way to update your api server is through

migrations.

Use robust migration tool

github.com / theory / squitch

• Follows a git-inspired workflow

• Models dependencies as a graph, not a line

• TDD at the SQL level!

• No conflicts between branches with git union merge strategy (unlike schema.rb)

Efficiency!

This can be much

faster than Rails

Efficiency! Use a fast language.

The web server itself doesn’t change so we

don’t need the convenience of a scripting

language.

Compile it once for your platform.

I’m using the Warp server on Haskell

Removing imperative cruft

Processing that happens in Ruby models is

glacially slow compared with tuned C inside

postgres.

Generate JSON inside Postgres

Dockyard measured that Postgres’ internal

JSON generation was 2X/10X faster than

ActiveRecord Serializers for small data and

160X faster for large data.

github.com/begriffs/postgrest

github.com/begriffs/postgrest-heroku

github.com/begriffs/postgrest-example