doc: media type handlers (#689)
* reference: media type handlers * Use function instead of computed field in editable task --------- Co-authored-by: Laurence Isla <lau.isla.c@gmail.com>
This commit is contained in:
co-authored by
Laurence Isla
parent
5c314e3f02
commit
b85ee953b7
@@ -23,13 +23,12 @@ To simplify things, we won't be using authentication, so grant all permissions o
|
||||
grant all on api.todos to web_anon;
|
||||
grant usage, select on sequence api.todos_id_seq to web_anon;
|
||||
|
||||
Next, add the ``text/html`` media type to the :ref:`raw-media-types` configuration.
|
||||
With this, PostgREST can identify the request made by your web browser (with the ``Accept: text/html`` header) and return a raw HTML document file.
|
||||
Next, add the ``text/html`` media type as a DOMAIN. With this, PostgREST can identify the request made by your web browser (with the ``Accept: text/html`` header)
|
||||
and return a raw HTML document file.
|
||||
|
||||
.. code-block:: ini
|
||||
.. code-block:: postgres
|
||||
|
||||
# tutorial.conf
|
||||
raw-media-types = "text/html"
|
||||
create domain "text/html" as text;
|
||||
|
||||
Creating an HTML Response
|
||||
-------------------------
|
||||
@@ -38,12 +37,8 @@ Let's create a function that returns a basic HTML file, using `Tailwind CSS <htt
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.index() returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
return $html$
|
||||
create or replace function api.index() returns "text/html" as $$
|
||||
select $html$
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -62,7 +57,7 @@ Let's create a function that returns a basic HTML file, using `Tailwind CSS <htt
|
||||
</body>
|
||||
</html>
|
||||
$html$;
|
||||
end $$;
|
||||
$$ language sql;
|
||||
|
||||
The web browser will open the web page at ``http://localhost:3000/rpc/index``.
|
||||
|
||||
@@ -77,9 +72,7 @@ Now, let's show a list of the to-dos already inserted in the database.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.html_todo(api.todos) returns text
|
||||
language sql stable
|
||||
as $$
|
||||
create or replace function api.html_todo(api.todos) returns text as $$
|
||||
select format($html$
|
||||
<li class="py-3">
|
||||
<span class="ml-2 %2$s">
|
||||
@@ -91,11 +84,9 @@ Now, let's show a list of the to-dos already inserted in the database.
|
||||
case when $1.done then 'line-through text-gray-400' else '' end,
|
||||
$1.task
|
||||
);
|
||||
$$;
|
||||
$$ language sql stable;
|
||||
|
||||
create or replace function api.html_all_todos() returns text
|
||||
language sql
|
||||
as $$
|
||||
create or replace function api.html_all_todos() returns text as $$
|
||||
select coalesce(
|
||||
'<ul id="todo-list" role="list" class="divide-y divide-gray-700 text-gray-100">'
|
||||
|| string_agg(api.html_todo(t), '' order by t.id) ||
|
||||
@@ -103,7 +94,7 @@ Now, let's show a list of the to-dos already inserted in the database.
|
||||
'<p class="text-gray-100">There is nothing else to do.</p>'
|
||||
)
|
||||
from api.todos t;
|
||||
$$;
|
||||
$$ language sql;
|
||||
|
||||
These two functions are used to build the to-do list template. We won't use them as PostgREST endpoints.
|
||||
|
||||
@@ -119,22 +110,13 @@ Next, let's add an endpoint to register a to-do in the database and modify the `
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.add_todo(_task text) returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
create or replace function api.add_todo(_task text) returns "text/html" as $$
|
||||
insert into api.todos(task) values (_task);
|
||||
return api.html_all_todos();
|
||||
end;
|
||||
$$;
|
||||
select api.html_all_todos();
|
||||
$$ language sql;
|
||||
|
||||
create or replace function api.index() returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
return $html$
|
||||
create or replace function api.index() returns "text/html" as $$
|
||||
select $html$
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -168,7 +150,7 @@ Next, let's add an endpoint to register a to-do in the database and modify the `
|
||||
</body>
|
||||
</html>
|
||||
$html$;
|
||||
end $$;
|
||||
$$ language sql;
|
||||
|
||||
- The ``/rpc/add_todo`` endpoint allows us to add a new to-do using the ``_task`` parameter and returns an ``html`` with all the to-dos in the database.
|
||||
|
||||
@@ -197,9 +179,7 @@ Now, let's modify ``api.html_todo`` and make it more functional.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.html_todo(api.todos) returns text
|
||||
language sql stable
|
||||
as $$
|
||||
create or replace function api.html_todo(api.todos) returns text as $$
|
||||
select format($html$
|
||||
<li class="py-3">
|
||||
<div class="flex justify-between items-center">
|
||||
@@ -216,8 +196,8 @@ Now, let's modify ``api.html_todo`` and make it more functional.
|
||||
</div>
|
||||
<div>
|
||||
<button class="p-1.5 rounded-full hover:bg-gray-700 focus:ring-gray-800"
|
||||
hx-get="/todos?select=html_editable_task"
|
||||
hx-vals='{"id": "eq.%1$s"}'
|
||||
hx-get="/rpc/html_editable_task"
|
||||
hx-vals='{"_id": "%1$s"}'
|
||||
hx-target="#todo-edit-area-%1$s"
|
||||
hx-trigger="click">
|
||||
<svg class="w-4 h-4 text-blue-300" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 18">
|
||||
@@ -243,7 +223,7 @@ Now, let's modify ``api.html_todo`` and make it more functional.
|
||||
$1.task,
|
||||
(not $1.done)::text
|
||||
);
|
||||
$$;
|
||||
$$ language sql stable;
|
||||
|
||||
Let's deconstruct the new htmx features added:
|
||||
|
||||
@@ -258,7 +238,7 @@ Let's deconstruct the new htmx features added:
|
||||
|
||||
- For the first ``<button>``:
|
||||
|
||||
+ ``hx-get="/todos?select=html_editable_task"``: it does an AJAX GET request to that endpoint.
|
||||
+ ``hx-get="/rpc/html_editable_task"``: it does an AJAX GET request to that endpoint.
|
||||
It returns an HTML with an input that will allow us to edit the task.
|
||||
|
||||
+ ``hx-target="#todo-edit-area"``: the returned HTML will replace the element with this id.
|
||||
@@ -272,13 +252,11 @@ Let's deconstruct the new htmx features added:
|
||||
+ ``hx-post="/rpc/delete_todo"``: this post request will delete the corresponding to-do.
|
||||
|
||||
Clicking on the first button will enable the task editing.
|
||||
That's why we create the ``api.html_editable_task`` :ref:`computed field <computed_cols>` and use the ``api.todos`` table as an endpoint:
|
||||
That's why we create the ``api.html_editable_task`` function as an endpoint:
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.html_editable_task(api.todos)
|
||||
returns text
|
||||
language sql as $$
|
||||
create or replace function api.html_editable_task(_id int) returns "text/html" as $$
|
||||
select format ($html$
|
||||
<form id="edit-task-%1$s"
|
||||
hx-post="/rpc/change_todo_task"
|
||||
@@ -290,47 +268,33 @@ That's why we create the ``api.html_editable_task`` :ref:`computed field <comput
|
||||
id="task-%1$s" type="text" name="_task" value="%2$s" autofocus>
|
||||
</form>
|
||||
$html$,
|
||||
$1.id,
|
||||
$1.task
|
||||
);
|
||||
$$;
|
||||
id,
|
||||
task
|
||||
)
|
||||
from api.todos
|
||||
where id = _id;
|
||||
$$ language sql;
|
||||
|
||||
We could use a function too, but this demonstrates that we can build HTML components (specially for a list) directly from a table by using computed fields.
|
||||
In this example, this will return an input field that allows us to edit the corresponding to-do task.
|
||||
|
||||
Finally, let's add the endpoints that will modify and delete the to-dos in the database.
|
||||
|
||||
.. code-block:: postgres
|
||||
|
||||
create or replace function api.change_todo_state(_id int, _done boolean) returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
create or replace function api.change_todo_state(_id int, _done boolean) returns "text/html" as $$
|
||||
update api.todos set done = _done where id = _id;
|
||||
return api.html_all_todos();
|
||||
end;
|
||||
$$;
|
||||
select api.html_all_todos();
|
||||
$$ language sql;
|
||||
|
||||
create or replace function api.change_todo_task(_id int, _task text) returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
create or replace function api.change_todo_task(_id int, _task text) returns "text/html" as $$
|
||||
update api.todos set task = _task where id = _id;
|
||||
return api.html_all_todos();
|
||||
end;
|
||||
$$;
|
||||
select api.html_all_todos();
|
||||
$$ language sql;
|
||||
|
||||
create or replace function api.delete_todo(_id int) returns text
|
||||
language plpgsql
|
||||
as $$
|
||||
begin
|
||||
perform set_config('response.headers','[{"Content-Type": "text/html; charset=utf-8"}]', true);
|
||||
create or replace function api.delete_todo(_id int) returns "text/html" as $$
|
||||
delete from api.todos where id = _id;
|
||||
return api.html_all_todos();
|
||||
end;
|
||||
$$;
|
||||
select api.html_all_todos();
|
||||
$$ language sql;
|
||||
|
||||
All of those functions return an HTML list of to-dos that will replace the outdated one:
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Media Type Handlers
|
||||
###################
|
||||
|
||||
PostgREST offers builtin handlers for common media types such as ``application/json`` and ``text/csv``. You can add handlers for other media types or override the builtin handlers.
|
||||
|
||||
Standard Media Types Handlers
|
||||
=============================
|
||||
|
||||
Builtins handlers are provided for the following standard media types:
|
||||
|
||||
* ``application/json``
|
||||
* ``text/csv``
|
||||
* ``application/geo+json``
|
||||
* ``application/x-www-form-urlencoded``
|
||||
* ``*/*``, uses the same handler as ``application/json``.
|
||||
|
||||
Vendor Media Types Handlers
|
||||
===========================
|
||||
|
||||
PostgREST also includes its own vendored media types, handlers for these are provided but cannot be overridden.
|
||||
|
||||
* ``application/vnd.pgrst.object``
|
||||
* ``application/vnd.pgrst.array``
|
||||
* ``application/vnd.pgrst.plan``
|
||||
|
||||
Custom Media Type Handlers
|
||||
==========================
|
||||
|
||||
TODO
|
||||
@@ -11,6 +11,7 @@ backoff
|
||||
balancer
|
||||
booleans
|
||||
Bouscal
|
||||
Builtins
|
||||
buildpack
|
||||
Bytea
|
||||
Cardano
|
||||
@@ -195,6 +196,7 @@ url
|
||||
urlencoded
|
||||
urls
|
||||
variadic
|
||||
vendored
|
||||
verifier
|
||||
versioning
|
||||
Vondra
|
||||
|
||||
Reference in New Issue
Block a user