SlideShare a Scribd company logo
1 of 35
Download to read offline
Relational DB to RESTful API
Taking the database seriously
Most web frameworks treat
the DB as a dumb store
This helps give them broad
appeal
What if we take a stand
instead?
??
? ?
?
Taking the database seriously
Is PostgreSQL powerful and
flexible enough to replace
the custom API server?
That’s my experiment
The Traditional Web API Stack
Your App
Web Server
Database
The Traditional Web API Stack
Your App
Web Server
Database
PostgREST
A no-configuration canonical
mapping from DB to HTTP
Talk Overview
The Traditional API Server (brief)
Live demo of PostgREST
What’s the SQL? How did
it do that?
The Traditional App
Handmade Nested
Routes
Controllers
Imperative code
ORM
Logic divorced from
data
What’s in an app?
HTTP request handling
Authentication
Authorization
Request Parsing
Request Validation
Database Communication
Database Response Handling
HTTP Response Building
With error handling woven
throughout...
Maintaining bespoke APIs gets old
“Most APIs look the
same, some have
icing, some have
fondant, some are
vanilla, some
chocolate. At the
core they’re all still
cakes.” -- Jett
Durham
Problem 1: Boilerplate
Want to add a new route?
Create model
Add each CRUD action
Check permissions
Support filtering, pagination
Special routes for joining data
Problem 2: No Single Source of Truth
Constraints are removed
from DB
No longer enforced
continuously + uniformly
Imperative code means
human must write docs
Authorization is per-
controller rather than
Problem 3: Hierarchy
Your info is relational, your routes
hierarchical
Say projects have parts and vice
versa.
Need routes for parts by project
and project by parts?
Other people recognize the
problem, hence GraphQL
Demo Time!
We’ll use the Pagila example database
It was ported from MySQL “Sakila”
It’s a DVD store with films, rentals, customers, payments,
categories, actors etc
A Tour of PostgREST
Security - Roles for Authorization
Anonymous Authenticator User(s)
Security - JWT for Authentication
YES
NO
Security - Roles in SQL
CREATE ROLE authenticator NOINHERIT LOGIN;
CREATE ROLE anon;
CREATE ROLE worker;
GRANT anon, worker TO authenticator;
Switching to a role
BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE;
SET LOCAL ROLE 'worker';
SET LOCAL "postgrest.claims.id" = 'jdoe';
-- ...
COMMIT;
Row-Level Security
PostgreSQL 9.5+ allows restricting access to individual rows
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
drop policy if exists authors_eigenedit on posts;
create policy authors_eigenedit on posts
using (true)
with check (
author = basic_auth.current_email()
);
Let’s see it in action
External Actions
You can’t do everything
inside SQL
How do you
● Send an email?
● Call a 3rd party
service?
LISTEN / NOTIFY
How to version the API?
So far OK but… but I don’t
want to couple the internal
schema with an API!
How to encapsulate true
schema?
How to version specific
endpoints?
Use database schemas
Internal Schema V1
table1
table2
table3
view2
proc
view2
HTTP Interface is Flexible
postgrest --schema v1
postgrest --schema v2,v1
postgrest --schema v3,v2,v1
Accept: application/json;
version=2
OR
GET /v2/...
Use the schema search-path
SET search_path TO v2, v1;
How does it work inside?
Warning: Boring / Cool
Generating the payload in 100% SQL
WITH pg_source AS
(SELECT "public"."festival".* FROM "public"."festival")
SELECT
(SELECT pg_catalog.count(1) FROM "public"."festival") AS total_result_set,
pg_catalog.count(t) AS page_total,
NULL AS header,
array_to_json(array_agg(row_to_json(t)))::character VARYING AS body
FROM
(SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
Adding a filter
WITH pg_source AS
(SELECT "public"."festival".* FROM "public"."festival"
WHERE "public"."festival"."name" LIKE '%fun%'::UNKNOWN)
SELECT
(SELECT pg_catalog.count(1) FROM "public"."festival"
WHERE "public"."festival"."name" LIKE '%fun%'::UNKNOWN) AS total_result_set,
pg_catalog.count(t) AS page_total,
NULL AS header,
array_to_json(array_agg(row_to_json(t)))::character varying AS body
FROM
(SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
Optimistic cast
Or without a global count
WITH pg_source AS
(SELECT "public"."festival".* FROM "public"."festival")
SELECT
NULL AS total_result_set,
pg_catalog.count(t) AS page_total,
NULL AS header,
array_to_json(array_agg(row_to_json(t)))::character varying AS body
FROM
(SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
Creating CSV body
-- ...
(SELECT string_agg(a.k, ',')
FROM
(SELECT json_object_keys(r)::TEXT AS k
FROM
(SELECT row_to_json(hh) AS r
FROM pg_source AS hh LIMIT 1) s
) a
) || 'n' ||
coalesce(
string_agg(
substring(t::text, 2, length(t::text) - 2), 'n'
), ''
)
-- ...
First row
Column names
Remove quotes
Embedding a relation
WITH pg_source AS
(SELECT "public"."film"."id", row_to_json("director".*) AS "director"
FROM "public"."film"
LEFT OUTER JOIN
(SELECT "public"."director".*
FROM "public"."director") AS "director"
ON "director"."name" = "film"."director")
SELECT
(SELECT pg_catalog.count(1) FROM "public"."film") AS total_result_set,
pg_catalog.count(t) AS page_total,
NULL AS header,
array_to_json(array_agg(row_to_json(t)))::character varying AS body
FROM
(SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
Embed row as field
Key(s) detected
ELSE
CASE
WHEN t.typelem <> 0::oid AND t.typlen = (-1)
THEN 'ARRAY'::text
WHEN nt.nspname = 'pg_catalog'::name THEN
format_type(a.atttypid, NULL::integer)
ELSE 'USER-DEFINED'::text
END
END::information_schema.character_data AS data_type,
information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*,
t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS character_maximum_length,
information_schema._pg_char_octet_length(information_schema._pg_truetypid(a.
*, t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS character_octet_length,
information_schema._pg_numeric_precision(information_schema._pg_truetypid(a.
*, t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS numeric_precision,
information_schema._pg_numeric_precision_radix(information_schema._pg_truety
pid(a.*, t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS numeric_precision_radix,
information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*,
t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS numeric_scale,
information_schema._pg_datetime_precision(information_schema._pg_truetypid(a
.*, t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.cardinal_number AS datetime_precision,
information_schema._pg_interval_type(information_schema._pg_truetypid(a.*,
t.*), information_schema._pg_truetypmod(a.*,
t.*))::information_schema.character_data AS interval_type,
NULL::integer::information_schema.cardinal_number AS
interval_precision,
NULL::character varying::information_schema.sql_identifier
AS character_set_catalog,
NULL::character varying::information_schema.sql_identifier
AS character_set_schema,
NULL::character varying::information_schema.sql_identifier
AS character_set_name,
SELECT DISTINCT
info.table_schema AS schema,
info.table_name AS table_name,
info.column_name AS name,
info.ordinal_position AS position,
info.is_nullable::boolean AS nullable,
info.data_type AS col_type,
info.is_updatable::boolean AS updatable,
info.character_maximum_length AS max_len,
info.numeric_precision AS precision,
info.column_default AS default_value,
array_to_string(enum_info.vals, ',') AS enum
FROM (
/*
-- CTE based on information_schema.columns to remove the owner filter
*/
WITH columns AS (
SELECT current_database()::information_schema.sql_identifier AS table_catalog,
nc.nspname::information_schema.sql_identifier AS table_schema,
c.relname::information_schema.sql_identifier AS table_name,
a.attname::information_schema.sql_identifier AS column_name,
a.attnum::information_schema.cardinal_number AS ordinal_position,
pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default,
CASE
WHEN a.attnotnull OR t.typtype = 'd'::"char" AND t.typnotnull THEN 'NO'::text
ELSE 'YES'::text
END::information_schema.yes_or_no AS is_nullable,
CASE
WHEN t.typtype = 'd'::"char" THEN
CASE
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype,
NULL::integer)
ELSE 'USER-DEFINED'::text
END
Matching up foreign keys
Deleting an item
WITH pg_source AS
(DELETE FROM "test"."items"
WHERE "test"."items"."id" = '1'::unknown
RETURNING "test"."items".*)
SELECT
'' AS total_result_set,
pg_catalog.count(t) AS page_total,
'',
''
FROM
(SELECT 1 FROM pg_source) t
Learning More
Read the Docs
http://postgrest.com
github.com / begriffs / postgrest

More Related Content

What's hot

ELK and FileBeat on OCI
ELK and FileBeat on OCIELK and FileBeat on OCI
ELK and FileBeat on OCIDonghuKIM2
 
Building day 2 upload Building the Internet of Things with Thingsquare and ...
Building day 2   upload Building the Internet of Things with Thingsquare and ...Building day 2   upload Building the Internet of Things with Thingsquare and ...
Building day 2 upload Building the Internet of Things with Thingsquare and ...Adam Dunkels
 
12 03 19_n7_openfoam_presentation_generale
12 03 19_n7_openfoam_presentation_generale12 03 19_n7_openfoam_presentation_generale
12 03 19_n7_openfoam_presentation_generaleCyprien Soulaine
 
The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습Hyun-woo Park
 
[GS네오텍] Google Cloud CDN
[GS네오텍] Google Cloud CDN[GS네오텍] Google Cloud CDN
[GS네오텍] Google Cloud CDNGS Neotek
 

What's hot (8)

Nfsu2 Cfginstaller
Nfsu2 CfginstallerNfsu2 Cfginstaller
Nfsu2 Cfginstaller
 
Ant, Maven and Jenkins
Ant, Maven and JenkinsAnt, Maven and Jenkins
Ant, Maven and Jenkins
 
ELK and FileBeat on OCI
ELK and FileBeat on OCIELK and FileBeat on OCI
ELK and FileBeat on OCI
 
Building day 2 upload Building the Internet of Things with Thingsquare and ...
Building day 2   upload Building the Internet of Things with Thingsquare and ...Building day 2   upload Building the Internet of Things with Thingsquare and ...
Building day 2 upload Building the Internet of Things with Thingsquare and ...
 
12 03 19_n7_openfoam_presentation_generale
12 03 19_n7_openfoam_presentation_generale12 03 19_n7_openfoam_presentation_generale
12 03 19_n7_openfoam_presentation_generale
 
The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습The MongoDB Strikes Back / MongoDB 의 역습
The MongoDB Strikes Back / MongoDB 의 역습
 
The Art Of Testing Trading Platforms From AppLabs
The Art Of Testing Trading Platforms From AppLabsThe Art Of Testing Trading Platforms From AppLabs
The Art Of Testing Trading Platforms From AppLabs
 
[GS네오텍] Google Cloud CDN
[GS네오텍] Google Cloud CDN[GS네오텍] Google Cloud CDN
[GS네오텍] Google Cloud CDN
 

Similar to A Tour of PostgREST

SQL Server - Introduction to TSQL
SQL Server - Introduction to TSQLSQL Server - Introduction to TSQL
SQL Server - Introduction to TSQLPeter Gfader
 
Expanding your impact with programmability in the data center
Expanding your impact with programmability in the data centerExpanding your impact with programmability in the data center
Expanding your impact with programmability in the data centerCisco Canada
 
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech Talks
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech TalksOracle to Amazon Aurora Migration, Step by Step - AWS Online Tech Talks
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech TalksAmazon Web Services
 
닷넷 개발자를 위한 패턴이야기
닷넷 개발자를 위한 패턴이야기닷넷 개발자를 위한 패턴이야기
닷넷 개발자를 위한 패턴이야기YoungSu Son
 
Seattle StrongLoop Node.js Workshop
Seattle StrongLoop Node.js WorkshopSeattle StrongLoop Node.js Workshop
Seattle StrongLoop Node.js WorkshopJimmy Guerrero
 
The 90-Day Startup with Google AppEngine for Java
The 90-Day Startup with Google AppEngine for JavaThe 90-Day Startup with Google AppEngine for Java
The 90-Day Startup with Google AppEngine for JavaDavid Chandler
 
OWB11gR2 - Extending ETL
OWB11gR2 - Extending ETL OWB11gR2 - Extending ETL
OWB11gR2 - Extending ETL Suraj Bang
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsPython RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsSolution4Future
 
Porting Applications From Oracle To PostgreSQL
Porting Applications From Oracle To PostgreSQLPorting Applications From Oracle To PostgreSQL
Porting Applications From Oracle To PostgreSQLPeter Eisentraut
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Fwdays
 
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...Insight Technology, Inc.
 
Engage 2023: Taking Domino Apps to the next level by providing a Rest API
Engage 2023: Taking Domino Apps to the next level by providing a Rest APIEngage 2023: Taking Domino Apps to the next level by providing a Rest API
Engage 2023: Taking Domino Apps to the next level by providing a Rest APISerdar Basegmez
 
Javazone 2010-lift-framework-public
Javazone 2010-lift-framework-publicJavazone 2010-lift-framework-public
Javazone 2010-lift-framework-publicTimothy Perrett
 
Choisir entre une API RPC, SOAP, REST, GraphQL? 
Et si le problème était ai...
Choisir entre une API  RPC, SOAP, REST, GraphQL?  
Et si le problème était ai...Choisir entre une API  RPC, SOAP, REST, GraphQL?  
Et si le problème était ai...
Choisir entre une API RPC, SOAP, REST, GraphQL? 
Et si le problème était ai...François-Guillaume Ribreau
 
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...NoSQLmatters
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Michael Renner
 

Similar to A Tour of PostgREST (20)

SQL Server - Introduction to TSQL
SQL Server - Introduction to TSQLSQL Server - Introduction to TSQL
SQL Server - Introduction to TSQL
 
Expanding your impact with programmability in the data center
Expanding your impact with programmability in the data centerExpanding your impact with programmability in the data center
Expanding your impact with programmability in the data center
 
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech Talks
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech TalksOracle to Amazon Aurora Migration, Step by Step - AWS Online Tech Talks
Oracle to Amazon Aurora Migration, Step by Step - AWS Online Tech Talks
 
Switch to Backend 2023
Switch to Backend 2023Switch to Backend 2023
Switch to Backend 2023
 
닷넷 개발자를 위한 패턴이야기
닷넷 개발자를 위한 패턴이야기닷넷 개발자를 위한 패턴이야기
닷넷 개발자를 위한 패턴이야기
 
Seattle StrongLoop Node.js Workshop
Seattle StrongLoop Node.js WorkshopSeattle StrongLoop Node.js Workshop
Seattle StrongLoop Node.js Workshop
 
Jdbc
JdbcJdbc
Jdbc
 
The 90-Day Startup with Google AppEngine for Java
The 90-Day Startup with Google AppEngine for JavaThe 90-Day Startup with Google AppEngine for Java
The 90-Day Startup with Google AppEngine for Java
 
Plproxy
PlproxyPlproxy
Plproxy
 
PPT
PPTPPT
PPT
 
OWB11gR2 - Extending ETL
OWB11gR2 - Extending ETL OWB11gR2 - Extending ETL
OWB11gR2 - Extending ETL
 
Python RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutionsPython RESTful webservices with Python: Flask and Django solutions
Python RESTful webservices with Python: Flask and Django solutions
 
Porting Applications From Oracle To PostgreSQL
Porting Applications From Oracle To PostgreSQLPorting Applications From Oracle To PostgreSQL
Porting Applications From Oracle To PostgreSQL
 
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
Maciej Treder "Server-side rendering with Angular—be faster and more SEO, CDN...
 
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...
[db tech showcase Tokyo 2017] C23: Lessons from SQLite4 by SQLite.org - Richa...
 
Engage 2023: Taking Domino Apps to the next level by providing a Rest API
Engage 2023: Taking Domino Apps to the next level by providing a Rest APIEngage 2023: Taking Domino Apps to the next level by providing a Rest API
Engage 2023: Taking Domino Apps to the next level by providing a Rest API
 
Javazone 2010-lift-framework-public
Javazone 2010-lift-framework-publicJavazone 2010-lift-framework-public
Javazone 2010-lift-framework-public
 
Choisir entre une API RPC, SOAP, REST, GraphQL? 
Et si le problème était ai...
Choisir entre une API  RPC, SOAP, REST, GraphQL?  
Et si le problème était ai...Choisir entre une API  RPC, SOAP, REST, GraphQL?  
Et si le problème était ai...
Choisir entre une API RPC, SOAP, REST, GraphQL? 
Et si le problème était ai...
 
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
Simon Elliston Ball – When to NoSQL and When to Know SQL - NoSQL matters Barc...
 
Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014Postgres Vienna DB Meetup 2014
Postgres Vienna DB Meetup 2014
 

Recently uploaded

Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxGDSC PJATK
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Will Schroeder
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfDaniel Santiago Silva Capera
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8DianaGray10
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.YounusS2
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1DianaGray10
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...DianaGray10
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024SkyPlanner
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesMd Hossain Ali
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Commit University
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureEric D. Schabell
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UbiTrack UK
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-pyJamie (Taka) Wang
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemAsko Soukka
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?IES VE
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintMahmoud Rabie
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...Aggregage
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IES VE
 

Recently uploaded (20)

Cybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptxCybersecurity Workshop #1.pptx
Cybersecurity Workshop #1.pptx
 
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
Apres-Cyber - The Data Dilemma: Bridging Offensive Operations and Machine Lea...
 
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdfIaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
IaC & GitOps in a Nutshell - a FridayInANuthshell Episode.pdf
 
201610817 - edge part1
201610817 - edge part1201610817 - edge part1
201610817 - edge part1
 
UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8UiPath Studio Web workshop series - Day 8
UiPath Studio Web workshop series - Day 8
 
Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.Basic Building Blocks of Internet of Things.
Basic Building Blocks of Internet of Things.
 
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1UiPath Platform: The Backend Engine Powering Your Automation - Session 1
UiPath Platform: The Backend Engine Powering Your Automation - Session 1
 
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
Connector Corner: Extending LLM automation use cases with UiPath GenAI connec...
 
Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024Salesforce Miami User Group Event - 1st Quarter 2024
Salesforce Miami User Group Event - 1st Quarter 2024
 
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just MinutesAI Fame Rush Review – Virtual Influencer Creation In Just Minutes
AI Fame Rush Review – Virtual Influencer Creation In Just Minutes
 
Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)Crea il tuo assistente AI con lo Stregatto (open source python framework)
Crea il tuo assistente AI con lo Stregatto (open source python framework)
 
OpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability AdventureOpenShift Commons Paris - Choose Your Own Observability Adventure
OpenShift Commons Paris - Choose Your Own Observability Adventure
 
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
UWB Technology for Enhanced Indoor and Outdoor Positioning in Physiological M...
 
20230104 - machine vision
20230104 - machine vision20230104 - machine vision
20230104 - machine vision
 
20230202 - Introduction to tis-py
20230202 - Introduction to tis-py20230202 - Introduction to tis-py
20230202 - Introduction to tis-py
 
Bird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystemBird eye's view on Camunda open source ecosystem
Bird eye's view on Camunda open source ecosystem
 
How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?How Accurate are Carbon Emissions Projections?
How Accurate are Carbon Emissions Projections?
 
Empowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership BlueprintEmpowering Africa's Next Generation: The AI Leadership Blueprint
Empowering Africa's Next Generation: The AI Leadership Blueprint
 
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
The Data Metaverse: Unpacking the Roles, Use Cases, and Tech Trends in Data a...
 
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
IESVE Software for Florida Code Compliance Using ASHRAE 90.1-2019
 

A Tour of PostgREST

  • 1. Relational DB to RESTful API
  • 2. Taking the database seriously Most web frameworks treat the DB as a dumb store This helps give them broad appeal What if we take a stand instead? ?? ? ? ?
  • 3. Taking the database seriously Is PostgreSQL powerful and flexible enough to replace the custom API server? That’s my experiment
  • 4. The Traditional Web API Stack Your App Web Server Database
  • 5. The Traditional Web API Stack Your App Web Server Database PostgREST A no-configuration canonical mapping from DB to HTTP
  • 6. Talk Overview The Traditional API Server (brief) Live demo of PostgREST What’s the SQL? How did it do that?
  • 7. The Traditional App Handmade Nested Routes Controllers Imperative code ORM Logic divorced from data
  • 8. What’s in an app? HTTP request handling Authentication Authorization Request Parsing Request Validation Database Communication Database Response Handling HTTP Response Building With error handling woven throughout...
  • 9. Maintaining bespoke APIs gets old “Most APIs look the same, some have icing, some have fondant, some are vanilla, some chocolate. At the core they’re all still cakes.” -- Jett Durham
  • 10. Problem 1: Boilerplate Want to add a new route? Create model Add each CRUD action Check permissions Support filtering, pagination Special routes for joining data
  • 11. Problem 2: No Single Source of Truth Constraints are removed from DB No longer enforced continuously + uniformly Imperative code means human must write docs Authorization is per- controller rather than
  • 12. Problem 3: Hierarchy Your info is relational, your routes hierarchical Say projects have parts and vice versa. Need routes for parts by project and project by parts? Other people recognize the problem, hence GraphQL
  • 13. Demo Time! We’ll use the Pagila example database It was ported from MySQL “Sakila” It’s a DVD store with films, rentals, customers, payments, categories, actors etc
  • 15. Security - Roles for Authorization Anonymous Authenticator User(s)
  • 16. Security - JWT for Authentication YES NO
  • 17. Security - Roles in SQL CREATE ROLE authenticator NOINHERIT LOGIN; CREATE ROLE anon; CREATE ROLE worker; GRANT anon, worker TO authenticator;
  • 18. Switching to a role BEGIN ISOLATION LEVEL READ COMMITTED READ WRITE; SET LOCAL ROLE 'worker'; SET LOCAL "postgrest.claims.id" = 'jdoe'; -- ... COMMIT;
  • 19. Row-Level Security PostgreSQL 9.5+ allows restricting access to individual rows ALTER TABLE posts ENABLE ROW LEVEL SECURITY; drop policy if exists authors_eigenedit on posts; create policy authors_eigenedit on posts using (true) with check ( author = basic_auth.current_email() );
  • 20. Let’s see it in action
  • 21. External Actions You can’t do everything inside SQL How do you ● Send an email? ● Call a 3rd party service? LISTEN / NOTIFY
  • 22. How to version the API? So far OK but… but I don’t want to couple the internal schema with an API! How to encapsulate true schema? How to version specific endpoints?
  • 23. Use database schemas Internal Schema V1 table1 table2 table3 view2 proc view2
  • 24. HTTP Interface is Flexible postgrest --schema v1 postgrest --schema v2,v1 postgrest --schema v3,v2,v1 Accept: application/json; version=2 OR GET /v2/...
  • 25. Use the schema search-path SET search_path TO v2, v1;
  • 26. How does it work inside? Warning: Boring / Cool
  • 27. Generating the payload in 100% SQL WITH pg_source AS (SELECT "public"."festival".* FROM "public"."festival") SELECT (SELECT pg_catalog.count(1) FROM "public"."festival") AS total_result_set, pg_catalog.count(t) AS page_total, NULL AS header, array_to_json(array_agg(row_to_json(t)))::character VARYING AS body FROM (SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
  • 28. Adding a filter WITH pg_source AS (SELECT "public"."festival".* FROM "public"."festival" WHERE "public"."festival"."name" LIKE '%fun%'::UNKNOWN) SELECT (SELECT pg_catalog.count(1) FROM "public"."festival" WHERE "public"."festival"."name" LIKE '%fun%'::UNKNOWN) AS total_result_set, pg_catalog.count(t) AS page_total, NULL AS header, array_to_json(array_agg(row_to_json(t)))::character varying AS body FROM (SELECT * FROM pg_source LIMIT ALL OFFSET 0) t Optimistic cast
  • 29. Or without a global count WITH pg_source AS (SELECT "public"."festival".* FROM "public"."festival") SELECT NULL AS total_result_set, pg_catalog.count(t) AS page_total, NULL AS header, array_to_json(array_agg(row_to_json(t)))::character varying AS body FROM (SELECT * FROM pg_source LIMIT ALL OFFSET 0) t
  • 30. Creating CSV body -- ... (SELECT string_agg(a.k, ',') FROM (SELECT json_object_keys(r)::TEXT AS k FROM (SELECT row_to_json(hh) AS r FROM pg_source AS hh LIMIT 1) s ) a ) || 'n' || coalesce( string_agg( substring(t::text, 2, length(t::text) - 2), 'n' ), '' ) -- ... First row Column names Remove quotes
  • 31. Embedding a relation WITH pg_source AS (SELECT "public"."film"."id", row_to_json("director".*) AS "director" FROM "public"."film" LEFT OUTER JOIN (SELECT "public"."director".* FROM "public"."director") AS "director" ON "director"."name" = "film"."director") SELECT (SELECT pg_catalog.count(1) FROM "public"."film") AS total_result_set, pg_catalog.count(t) AS page_total, NULL AS header, array_to_json(array_agg(row_to_json(t)))::character varying AS body FROM (SELECT * FROM pg_source LIMIT ALL OFFSET 0) t Embed row as field Key(s) detected
  • 32. ELSE CASE WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer) ELSE 'USER-DEFINED'::text END END::information_schema.character_data AS data_type, information_schema._pg_char_max_length(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_maximum_length, information_schema._pg_char_octet_length(information_schema._pg_truetypid(a. *, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS character_octet_length, information_schema._pg_numeric_precision(information_schema._pg_truetypid(a. *, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision, information_schema._pg_numeric_precision_radix(information_schema._pg_truety pid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_precision_radix, information_schema._pg_numeric_scale(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS numeric_scale, information_schema._pg_datetime_precision(information_schema._pg_truetypid(a .*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.cardinal_number AS datetime_precision, information_schema._pg_interval_type(information_schema._pg_truetypid(a.*, t.*), information_schema._pg_truetypmod(a.*, t.*))::information_schema.character_data AS interval_type, NULL::integer::information_schema.cardinal_number AS interval_precision, NULL::character varying::information_schema.sql_identifier AS character_set_catalog, NULL::character varying::information_schema.sql_identifier AS character_set_schema, NULL::character varying::information_schema.sql_identifier AS character_set_name, SELECT DISTINCT info.table_schema AS schema, info.table_name AS table_name, info.column_name AS name, info.ordinal_position AS position, info.is_nullable::boolean AS nullable, info.data_type AS col_type, info.is_updatable::boolean AS updatable, info.character_maximum_length AS max_len, info.numeric_precision AS precision, info.column_default AS default_value, array_to_string(enum_info.vals, ',') AS enum FROM ( /* -- CTE based on information_schema.columns to remove the owner filter */ WITH columns AS ( SELECT current_database()::information_schema.sql_identifier AS table_catalog, nc.nspname::information_schema.sql_identifier AS table_schema, c.relname::information_schema.sql_identifier AS table_name, a.attname::information_schema.sql_identifier AS column_name, a.attnum::information_schema.cardinal_number AS ordinal_position, pg_get_expr(ad.adbin, ad.adrelid)::information_schema.character_data AS column_default, CASE WHEN a.attnotnull OR t.typtype = 'd'::"char" AND t.typnotnull THEN 'NO'::text ELSE 'YES'::text END::information_schema.yes_or_no AS is_nullable, CASE WHEN t.typtype = 'd'::"char" THEN CASE WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer) ELSE 'USER-DEFINED'::text END Matching up foreign keys
  • 33. Deleting an item WITH pg_source AS (DELETE FROM "test"."items" WHERE "test"."items"."id" = '1'::unknown RETURNING "test"."items".*) SELECT '' AS total_result_set, pg_catalog.count(t) AS page_total, '', '' FROM (SELECT 1 FROM pg_source) t
  • 34. Learning More Read the Docs http://postgrest.com
  • 35. github.com / begriffs / postgrest