chore: improve intro of media type handlers

This commit is contained in:
steve-chavez
2023-12-01 10:51:46 -05:00
parent 49903ca6db
commit ee4321623f
2 changed files with 48 additions and 20 deletions
+47 -20
View File
@@ -3,7 +3,7 @@
Media Type Handlers
###################
Media Type Handlers allows PostgREST to deliver custom media types. These handlers extend the :ref:`builtin ones <builtin_media>` and can also override them.
Media Type Handlers allow PostgREST to deliver custom media types. These handlers extend the :ref:`builtin ones <builtin_media>` and can also override them.
Media types are expressed as type aliases using `domains <https://www.postgresql.org/docs/current/sql-createdomain.html>`_ and their name must comply to `RFC 6838 requirements <https://datatracker.ietf.org/doc/html/rfc6838#section-4.2>`_.
@@ -11,11 +11,7 @@ Media types are expressed as type aliases using `domains <https://www.postgresql
CREATE DOMAIN "application/json" AS json;
By using these domains as return types:
- Of :ref:`Functions <s_procs>`, these will turn into handlers.
- Of `Aggregates <https://www.postgresql.org/docs/current/sql-createaggregate.html>`_ transition or final functions, these will serve as handlers for :ref:`tables_views` and :ref:`table_functions`.
Using these domains, :ref:`functions <s_procs>` can become handlers and `user-defined aggregates <https://www.postgresql.org/docs/current/xaggr.html>`_ can serve as handlers for :ref:`tables_views` and :ref:`table_functions`.
.. note::
@@ -38,12 +34,16 @@ As an example, let's obtain the `TWKB <https://postgis.net/docs/ST_AsTWKB.html>`
insert into lines values (1, 'line-1', 'LINESTRING(1 1,5 5)'::geometry), (2, 'line-2', 'LINESTRING(2 2,6 6)'::geometry);
For this you can create a vendor media type and use it as a return type on a function.
For this you can create a vendor media type.
.. code-block:: postgres
create domain "application/vnd.twkb" as bytea;
And use it as a return type on a function, to make it a handler.
.. code-block:: postgres
create or replace function get_line (id int)
returns "application/vnd.twkb" as $$
select st_astwkb(geom) from lines where id = get_line.id;
@@ -70,29 +70,39 @@ Note that PostgREST will automatically set the ``Content-Type`` to ``applicatio
Handlers for Tables/Views
=========================
To benefit from a compressed format like ``TWKB``, it makes more sense to obtain many rows instead of one. Let's allow that by adding a handler for the table. You'll need an aggregate:
To benefit from a compressed format like ``TWKB``, it makes more sense to obtain many rows instead of one. Let's allow that by adding a handler for the table.
User-defined aggregates can be turned into handlers by using domain media types as the return type of their transition or final functions.
Let's create a transition function for this example.
.. code-block:: postgres
-- let's add the vendor type as return of the transition function
create or replace function twkb_handler_transition (state bytea, next lines)
returns "application/vnd.twkb" as $$
select state || st_astwkb(next.geom);
$$ language sql;
-- use the transition function on the aggregate
Now we'll use it on a new aggregate defined for the ``lines`` table.
.. code-block:: postgres
create or replace aggregate twkb_agg (lines) (
initcond = ''
, stype = "application/vnd.twkb"
, sfunc = twkb_handler_transition
);
-- quick test
-- SELECT twkb_agg(l) from lines l;
-- twkb_agg
------------------------------------------------------------------
-- \xa20002c09a0cc09a0c80ea3080ea30a2000280b51880b51880ea3080ea30
--(1 row)
Make a quick test on SQL to see it working.
.. code-block:: psql
SELECT twkb_agg(l) from lines l;
twkb_agg
---------------------------------------------------------------
\xa20002c09a0cc09a0c80ea3080ea30a2000280b51880b51880ea3080ea30
(1 row)
Now you can request the table endpoint with the ``twkb`` media type:
@@ -129,17 +139,27 @@ Overriding a Builtin Handler
============================
Let's override the existing ``text/csv`` handler for the table to provide a more complex CSV output.
It'll include a `Byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>`_ plus a ``Content-Disposition`` header to set a name for the downloaded file.
It'll include a `Byte order mark (BOM) <https://en.wikipedia.org/wiki/Byte_order_mark>`_ plus a ``Content-Disposition`` header to set a name for the downloaded file.
Create a domain for the standard ``text/csv`` media type.
.. code-block:: postgres
create domain "text/csv" as text;
And a transition function that returns the domain.
.. code-block:: postgres
create or replace function bom_csv_trans (state text, next lines)
returns "text/csv" as $$
select state || next.id::text || ',' || next.name || ',' || next.geom::text || E'\n';
$$ language sql;
This time we'll add a final function. This will add the CSV header, the BOM and the ``Content-Disposition`` header.
.. code-block:: postgres
create or replace function bom_csv_final (data "text/csv")
returns "text/csv" as $$
-- set the Content-Disposition header
@@ -151,6 +171,10 @@ It'll include a `Byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>
(E'id,name,geom\n' || data);
$$ language sql;
Now use the transition and final function as part of the new aggregate.
.. code-block:: postgres
create or replace aggregate bom_csv_agg (lines) (
initcond = ''
, stype = "text/csv"
@@ -158,7 +182,7 @@ It'll include a `Byte order mark <https://en.wikipedia.org/wiki/Byte_order_mark>
, finalfunc = bom_csv_final
);
You can now request it like:
And request it like:
.. code-block:: bash
@@ -188,15 +212,17 @@ Let's define an any handler for a view that will always respond with ``XML`` out
create domain "*/*" as pg_catalog.xml;
-- we'll use an .xml suffix for the view to be clear it's output is always XML
-- we'll use an .xml suffix for the view to be clear its output is always XML
create view "lines.xml" as
select * from lines;
-- transition function
create or replace function lines_xml_trans (state "*/*", next "lines.xml")
returns "*/*" as $$
select xmlconcat(state, xmlelement(name line, xmlattributes(next.id as id, next.name as name), next.geom));
$$ language sql;
-- final function
create or replace function lines_xml_final (data "*/*")
returns "*/*" as $$
declare
@@ -214,7 +240,8 @@ Let's define an any handler for a view that will always respond with ``XML`` out
return data;
end; $$ language plpgsql;
create or replace aggregate testlines_xml_agg ("lines.xml") (
-- new aggregate
create or replace aggregate lines_xml_agg ("lines.xml") (
stype = "*/*"
, sfunc = lines_xml_trans
, finalfunc = lines_xml_final
+1
View File
@@ -11,6 +11,7 @@ backoff
balancer
booleans
buildpack
BOM
Bytea
Cardano
cd