mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
Merge branch 'master' of github.com:supabase/supabase
This commit is contained in:
commit
d8168bf613
4 files changed
+431
-1
No files matched your search
@@ -0,0 +1,74 @@
|
||||
---
|
||||
id: webhooks
|
||||
title: 'Database Webhooks'
|
||||
description: Trigger external payloads on database events.
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
Database Webhooks allow you to send real-time data from your database to another system whenever a table event occurs.
|
||||
|
||||
|
||||
You can hook into three table events: `INSERT`, `UPDATE`, and `DELETE`. All events are fired _after_ a database row is changed.
|
||||
|
||||
Database Webhooks are very similar to triggers, and that's because Database Webhooks are just a convenience wrapper around triggers
|
||||
using the [pg_net](/docs/guides/database/extensions/pgnet) extension. This extension is asynchronous, and therefore will not block your database changes for long-running network requests.
|
||||
|
||||
This video demonstrates how you can create a new customer in Stripe each time a row is inserted into a `profiles` table:
|
||||
|
||||
:::note
|
||||
|
||||
Database Webhooks were previously known as Function Hooks.
|
||||
|
||||
:::
|
||||
|
||||
<div class="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/codAs9-NeHM"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Creating a webhook
|
||||
|
||||
1. Create a new [Database Webhook](https://app.supabase.com/project/_/database/hooks) in the Dashboard.
|
||||
1. Give your Webhook a name.
|
||||
1. Select the table you want to hook into.
|
||||
1. Select one or more events (table inserts, updates, or deletes) you want to hook into.
|
||||
|
||||
We currently support HTTP webhooks. These are sent as a `POST` request with a JSON payload.
|
||||
|
||||
## Payload
|
||||
|
||||
The payload is automatically generated from the underlying table record:
|
||||
|
||||
```typescript
|
||||
type InsertPayload = {
|
||||
type: 'INSERT'
|
||||
table: string
|
||||
schema: string
|
||||
record: TableRecord<T>
|
||||
old_record: null
|
||||
}
|
||||
type UpdatePayload = {
|
||||
type: 'UPDATE'
|
||||
table: string
|
||||
schema: string
|
||||
record: TableRecord<T>
|
||||
old_record: TableRecord<T>
|
||||
}
|
||||
type DeletePayload = {
|
||||
type: 'DELETE'
|
||||
table: string
|
||||
schema: string
|
||||
record: null
|
||||
old_record: TableRecord<T>
|
||||
}
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [pg_net](/docs/guides/database/extensions/pgnet): an async networking extension for PostgreSQL
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
id: pgcron
|
||||
title: 'pg_cron: Job Scheduling'
|
||||
description: 'pgnet: a simple cron-based job scheduler for PostgreSQL that runs inside the database.'
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
The `pg_cron` extension is a simple cron-based job scheduler for PostgreSQL that runs inside the database.
|
||||
|
||||
## Usage
|
||||
|
||||
### Enable the extension
|
||||
|
||||
<Tabs
|
||||
defaultValue="dashboard"
|
||||
values={[
|
||||
{label: 'Dashboard', value: 'dashboard'},
|
||||
{label: 'SQL', value: 'sql'},
|
||||
]}>
|
||||
|
||||
<TabItem value="dashboard">
|
||||
|
||||
1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
|
||||
2. Click on **Extensions** in the sidebar.
|
||||
3. Search for "pg_cron" and enable the extension.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="sql">
|
||||
|
||||
```sql
|
||||
-- Example: enable the "pg_cron" extension
|
||||
create extension pg_cron with schema extensions;
|
||||
|
||||
-- If you're planning to use a non-superuser role to schedule jobs,
|
||||
-- ensure that they are granted access to the cron schema and its underlying objects beforehand.
|
||||
-- Failure to do so would result in jobs by these roles to not run at all.
|
||||
|
||||
grant usage on schema cron to {{DB user}};
|
||||
grant all privileges on all tables in schema cron to {{DB user}};
|
||||
|
||||
|
||||
-- Example: disable the "pg_cron" extension
|
||||
drop extension if exists pg_cron;
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Syntax
|
||||
|
||||
The schedule uses the standard cron syntax, in which \* means "run every time period", and a specific number means "but only at this time":
|
||||
|
||||
```bash
|
||||
┌───────────── min (0 - 59)
|
||||
│ ┌────────────── hour (0 - 23)
|
||||
│ │ ┌─────────────── day of month (1 - 31)
|
||||
│ │ │ ┌──────────────── month (1 - 12)
|
||||
│ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
|
||||
│ │ │ │ │ Saturday, or use names; 7 is also Sunday)
|
||||
│ │ │ │ │
|
||||
│ │ │ │ │
|
||||
* * * * *
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Delete data every week
|
||||
|
||||
Delete old data on Saturday at 3:30am (GMT):
|
||||
|
||||
```sql
|
||||
select cron.schedule (
|
||||
'webhook-every-minute', -- name of the cron job
|
||||
'* * * * *', -- every minute
|
||||
$$ delete from events where event_time < now() - interval '1 week' $$
|
||||
);
|
||||
```
|
||||
|
||||
### Run a vacuum every day
|
||||
|
||||
Vacuum every day at 3:00am (GMT)
|
||||
|
||||
```sql
|
||||
SELECT cron.schedule('nightly-vacuum', '0 3 * * *', 'VACUUM');
|
||||
```
|
||||
|
||||
### Unschedule a job
|
||||
|
||||
Unschedules a job called `'nightly-vacuum'`
|
||||
|
||||
```sql
|
||||
SELECT cron.unschedule('nightly-vacuum');
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [pg_cron GitHub Repository](https://github.com/citusdata/pg_cron)
|
||||
@@ -0,0 +1,254 @@
|
||||
---
|
||||
id: pgnet
|
||||
title: 'pg_net: Async Networking'
|
||||
description: 'pg_net: an async networking extension for PostgreSQL.'
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
:::caution
|
||||
|
||||
The pg_net API is in beta. Functions signatures may change.
|
||||
|
||||
:::
|
||||
|
||||
[pg_net](https://github.com/supabase/pg_net/) is a PostgreSQL extension exposing a SQL interface for async networking with a focus on scalability and UX.
|
||||
|
||||
It differs from the `http` extension in that it is asynchronous by default. This makes it useful in blocking functions (like triggers).
|
||||
|
||||
## Usage
|
||||
|
||||
### Enable the extension
|
||||
|
||||
<Tabs
|
||||
defaultValue="dashboard"
|
||||
values={[
|
||||
{label: 'Dashboard', value: 'dashboard'},
|
||||
{label: 'SQL', value: 'sql'},
|
||||
]}>
|
||||
|
||||
<TabItem value="dashboard">
|
||||
|
||||
1. Go to the [Database](https://app.supabase.com/project/_/database/tables) page in the Dashboard.
|
||||
2. Click on **Extensions** in the sidebar.
|
||||
3. Search for "pg_net" and enable the extension.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="sql">
|
||||
|
||||
```sql
|
||||
-- Example: enable the "pg_net" extension
|
||||
create schema if not exists net;
|
||||
create extension pg_net with schema net;
|
||||
|
||||
-- Example: disable the "plv8" extension
|
||||
drop extension if exists pg_net;
|
||||
drop schema net;
|
||||
```
|
||||
|
||||
Even though the SQL code is `create extension`, this is the equivalent of "enabling the extension".
|
||||
To disable an extension, call `drop extension`.
|
||||
|
||||
Procedural languages are automatically installed within `pg_catalog`, so you don't need to specify a schema.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## `http_get` {#http_get}
|
||||
|
||||
Creates an HTTP GET request returning the request's ID. HTTP requests are not started until the transaction is committed.
|
||||
|
||||
### Signature
|
||||
|
||||
:::caution
|
||||
|
||||
This is a Postgres SECURITY DEFINER function.
|
||||
|
||||
:::
|
||||
|
||||
```sql
|
||||
net.http_get(
|
||||
-- url for the request
|
||||
url text,
|
||||
-- key/value pairs to be url encoded and appended to the `url`
|
||||
params jsonb default '{}'::jsonb,
|
||||
-- key/values to be included in request headers
|
||||
headers jsonb default '{}'::jsonb,
|
||||
-- WARNING: this is currently ignored, so there is no timeout
|
||||
-- the maximum number of milliseconds the request may take before being cancelled
|
||||
timeout_milliseconds int default 1000
|
||||
)
|
||||
-- request_id reference
|
||||
returns bigint
|
||||
|
||||
strict
|
||||
volatile
|
||||
parallel safe
|
||||
language plpgsql
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sql
|
||||
select net.http_get('https://news.ycombinator.com') as request_id;
|
||||
request_id
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
```
|
||||
|
||||
After triggering `http_get`, use [`http_get_result`](#http_get_result) to get the result of the request.
|
||||
|
||||
## `http_post` {#http_post}
|
||||
|
||||
Creates an HTTP POST request with a JSON body, returning the request's ID. HTTP requests are not started until the transaction is committed.
|
||||
|
||||
The body's character set encoding matches the database's `server_encoding` setting.
|
||||
|
||||
### Signature
|
||||
|
||||
:::caution
|
||||
|
||||
This is a Postgres SECURITY DEFINER function
|
||||
|
||||
:::
|
||||
|
||||
```sql
|
||||
net.http_post(
|
||||
-- url for the request
|
||||
url text,
|
||||
-- body of the POST request
|
||||
body jsonb default '{}'::jsonb,
|
||||
-- key/value pairs to be url encoded and appended to the `url`
|
||||
params jsonb default '{}'::jsonb,
|
||||
-- key/values to be included in request headers
|
||||
headers jsonb default '{"Content-Type": "application/json"}'::jsonb,
|
||||
-- WARNING: this is currently ignored, so there is no timeout
|
||||
-- the maximum number of milliseconds the request may take before being cancelled
|
||||
timeout_milliseconds int default 1000
|
||||
)
|
||||
-- request_id reference
|
||||
returns bigint
|
||||
|
||||
volatile
|
||||
parallel safe
|
||||
language plpgsql
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```sql
|
||||
select
|
||||
net.http_post(
|
||||
url:='https://httpbin.org/post',
|
||||
body:='{"hello": "world"}'::jsonb
|
||||
) as request_id;
|
||||
request_id
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
```
|
||||
|
||||
After triggering `http_post`, use [`http_get_result`](#http_get_result) to get the result of the request.
|
||||
|
||||
## `http_collect_response` {#http_collect_response}
|
||||
|
||||
Given a `request_id` reference, retrieves the response.
|
||||
|
||||
When `async:=false` is set it is recommended that [statement_timeout](https://www.postgresql.org/docs/13/runtime-config-client.html) is set for the maximum amount of time the caller is willing to wait in case the response is slow to populate.
|
||||
|
||||
### Signature
|
||||
|
||||
:::caution
|
||||
|
||||
This is a Postgres SECURITY DEFINER function
|
||||
|
||||
:::
|
||||
|
||||
```sql
|
||||
net.http_collect_response(
|
||||
-- request_id reference
|
||||
request_id bigint,
|
||||
-- when `true`, return immediately. when `false` wait for the request to complete before returning
|
||||
async bool default true
|
||||
)
|
||||
-- http response composite wrapped in a result type
|
||||
returns net.http_response_result
|
||||
|
||||
strict
|
||||
volatile
|
||||
parallel safe
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
:::caution
|
||||
|
||||
`net.http_collect_response` must be in a separate transaction from the calls to `net.http_<method>`
|
||||
|
||||
:::
|
||||
|
||||
```sql
|
||||
select
|
||||
net.http_post(
|
||||
url:='https://httpbin.org/post',
|
||||
body:='{"hello": "world"}'::jsonb
|
||||
) as request_id;
|
||||
request_id
|
||||
----------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
select * from net.http_collect_response(1, async:=false);
|
||||
status | message | response
|
||||
--------+---------+----------
|
||||
SUCCESS ok (
|
||||
status_code := 200,
|
||||
headers := '{"date": ...}',
|
||||
body := '{"args": ...}'
|
||||
)::net.http_response_result
|
||||
|
||||
|
||||
select
|
||||
(response).body::json
|
||||
from
|
||||
net.http_collect_response(request_id:=1);
|
||||
body
|
||||
-------------------------------------------------------------------
|
||||
{
|
||||
"args": {},
|
||||
"data": "{\"hello\": \"world\"}",
|
||||
"files": {},
|
||||
"form": {},
|
||||
"headers": {
|
||||
"Accept": "*/*",
|
||||
"Content-Length": "18",
|
||||
"Content-Type": "application/json",
|
||||
"Host": "httpbin.org",
|
||||
"User-Agent": "pg_net/0.2",
|
||||
"X-Amzn-Trace-Id": "Root=1-61031a5c-7e1afeae69bffa8614d8e48e"
|
||||
},
|
||||
"json": {
|
||||
"hello": "world"
|
||||
},
|
||||
"origin": "135.63.38.488",
|
||||
"url": "https://httpbin.org/post"
|
||||
}
|
||||
(1 row)
|
||||
```
|
||||
|
||||
Where `response` is a composite:
|
||||
|
||||
```sql
|
||||
status_code integer
|
||||
headers jsonb
|
||||
body text
|
||||
```
|
||||
|
||||
Possible values for `net.http_response_result.status` are `('PENDING', 'SUCCESS', 'ERROR')`
|
||||
|
||||
## Resources
|
||||
|
||||
- Source code: [github.com/supabase/pg_net](https://github.com/supabase/pg_net/)
|
||||
- Official Docs: [supabase.github.io/pg_net](https://supabase.github.io/pg_net/)
|
||||
@@ -124,6 +124,7 @@ const sidebars = {
|
||||
'guides/database/connecting-to-postgres',
|
||||
'guides/database/tables',
|
||||
'guides/database/functions',
|
||||
'guides/database/webhooks',
|
||||
'guides/database/full-text-search',
|
||||
'guides/database/migrating-between-projects',
|
||||
// 'guides/database/json',
|
||||
@@ -135,9 +136,11 @@ const sidebars = {
|
||||
collapsed: true,
|
||||
items: [
|
||||
'guides/database/extensions',
|
||||
'guides/database/extensions/plv8',
|
||||
'guides/database/extensions/http',
|
||||
'guides/database/extensions/pgcron',
|
||||
'guides/database/extensions/pgnet',
|
||||
'guides/database/extensions/pgtap',
|
||||
'guides/database/extensions/plv8',
|
||||
'guides/database/extensions/uuid-ossp',
|
||||
],
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user