公开的架构中的所有视图和表均可被查询的活动数据库角色访问,并且可供活动数据库角色访问。它们暴露在一级深度路线中。例如,表格人员的全部内容都在返回
GET /people HTTP/1.1
没有深层/嵌套/路线。每个路由都完全根据数据库权限提供OPTIONS,GET,POST,PATCH和DELETE动词。
注意
为什么不提供嵌套路线?许多API允许嵌套检索相关信息,例如/films/1/director
。我们提供了一种更灵活的机制(受GraphQL启发)来嵌入相关信息。它可以处理一对多和多对多关系。关于资源嵌入的部分对此进行了介绍。
您可以通过在列上添加条件来过滤结果行,每个条件都有一个查询字符串参数。例如,要返回13岁以下的人:
GET /people?age=lt.13 HTTP/1.1
多个参数可以通过以下方式逻辑组合:
GET /people?age=gte.18&student=is.true HTTP/1.1
多个参数可以通过以下方式在逻辑上脱节:
GET /people?or=(age.gte.14,age.lte.18) HTTP/1.1
也可以应用复杂的逻辑:
GET /people?and=(grade.gte.90,student.is.true,or(age.gte.14,age.is.null)) HTTP/1.1
这些运算符可用:
Abbreviation | In PostgreSQL | Meaning |
---|---|---|
eq | = | equals |
gt | > | greater than |
gte | >= | greater than or equal |
lt | < | less than |
lte | <&#61; | less than or equal |
neq | <> or !&#61; | not equal |
like | LIKE | LIKE operator (use * in place of %) |
ilike | ILIKE | ILIKE operator (use * in place of %) |
in | IN | one of a list of values, e.g. ?a&#61;in.(1,2,3) – also supports commas in quoted strings like ?a&#61;in.("hi,there","yes,you") |
is | IS | checking for exact equality (null,true,false) |
fts | &#64;&#64; | Full-Text Search using to_tsquery |
plfts | &#64;&#64; | Full-Text Search using plainto_tsquery |
phfts | &#64;&#64; | Full-Text Search using phraseto_tsquery |
wfts | &#64;&#64; | Full-Text Search using websearch_to_tsquery |
cs | &#64;> | contains e.g. ?tags&#61;cs.{example, new} |
cd | <&#64; | contained in e.g. ?values&#61;cd.{1,2,3} |
ov | && | overlap (have points in common), e.g. ?period&#61;ov.[2017-01-01,2017-06-30] – also supports array types, use curly braces instead of square brackets e.g. :code: ?arr&#61;ov.{1,3} |
sl | << | strictly left of, e.g. ?range&#61;sl.(1,10) |
sr | >> | strictly right of |
nxr | &< | does not extend to the right of, e.g. ?range&#61;nxr.(1,10) |
nxl | &> | does not extend to the left of |
adj | -|- | is adjacent to, e.g. ?range&#61;adj.(1,10) |
not | NOT | negates another operator, see below |
not
like ?a&#61;not.eq.2
或?not.and&#61;(a.gte.0,a.lte.100)
。对于更复杂的过滤器&#xff0c;您将必须在数据库中创建一个新视图&#xff0c;或使用存储过程。例如&#xff0c;下面是一个显示“今天的故事”的视图&#xff0c;其中可能包括较旧的固定故事&#xff1a;
CREATE VIEW fresh_stories AS
SELECT *FROM storiesWHERE pinned &#61; trueOR published > now() - interval &#39;1 day&#39;
ORDER BY pinned DESC, published DESC;
该视图将提供一个新的端点&#xff1a;
GET /fresh_stories HTTP/1.1
重要
使用视图所有者的特权来调用视图&#xff0c;这与带有该选项的存储过程非常相似。由SUPERUSER角色创建时&#xff0c;除非指定了不同的非SUPERUSER所有者&#xff0c;否则所有行级安全性都将被绕过。SECURITY DEFINER
-- Workaround:
-- non-SUPERUSER role to be used as the owner of the views
CREATE ROLE api_views_owner;
-- alter the view owner so RLS can work normally
ALTER VIEW sample_view OWNER TO api_views_owner;
fts
上面提到的过滤器有很多选项来支持灵活的文本查询&#xff0c;即选择普通搜索还是词组搜索以及用于词干的语言。假设这tsearch
是一个列my_tsv
类型为tsvector的表。以下示例说明了可能性。
GET /tsearch?my_tsv&#61;fts(french).amusant HTTP/1.1
GET /tsearch?my_tsv&#61;plfts.The%20Fat%20Cats HTTP/1.1
GET /tsearch?my_tsv&#61;not.phfts(english).The%20Fat%20Cats HTTP/1.1
GET /tsearch?my_tsv&#61;not.wfts(french).amusant HTTP/1.1
使用词组搜索模式要求PostgreSQL的版本至少为9.6&#xff0c;并且将在数据库的早期版本中引发错误。
使用websearch_to_tsquery需要PostgreSQL的版本至少为11.0&#xff0c;并且会在数据库的早期版本中引发错误。
当某些列很宽时&#xff08;例如那些保存二进制数据的列&#xff09;&#xff0c;服务器在响应中保留它们会更有效。客户端可以使用select
参数指定需要哪些列。
GET /people?select&#61;first_name,age HTTP/1.1[{"first_name": "John", "age": 30},{"first_name": "Jane", "age": 20}
]
默认值为*
&#xff0c;表示所有列。在“ 资源嵌入”中&#xff0c;此值将变得更加重要。
您可以通过在列之前添加别名和冒号:
运算符来对列进行重命名。
GET /people?select&#61;fullName:full_name,birthDate:birth_date HTTP/1.1[{"fullName": "John Doe", "birthDate": "04/25/1988"},{"fullName": "Jane Doe", "birthDate": "01/12/1998"}
]
通过在双冒号::
加所需类型的后缀后缀&#xff0c;可以铸造柱。
GET /people?select&#61;full_name,salary::text HTTP/1.1[{"full_name": "John Doe", "salary": "90000.00"},{"full_name": "Jane Doe", "salary": "120000.00"}
]
您可以根据PostgreSQL docs使用箭头运算符&#xff08;或&#xff09;指定json
或jsonb
列的路径。->
->>
GET /people?select&#61;id,json_data->>blood_type,json_data->phones HTTP/1.1[{ "id": 1, "blood_type": "A&#43;", "phones": [{"country_code": "61", "number": "917-929-5745"}] },{ "id": 2, "blood_type": "O&#43;", "phones": [{"country_code": "43", "number": "512-446-4988"}, {"country_code": "43", "number": "213-891-5979"}] }
]
GET /people?select&#61;id,json_data->phones->0->>number HTTP/1.1[{ "id": 1, "number": "917-929-5745"},{ "id": 2, "number": "512-446-4988"}
]
过滤器可以应用于计算列&#xff08;也称为虚拟列&#xff09;以及实际的表/视图列&#xff0c;即使计算列不会出现在输出中。例如&#xff0c;要一次搜索名字和姓氏&#xff0c;我们可以创建一个计算列&#xff0c;该列将不会出现在输出中&#xff0c;但可以在过滤器中使用&#xff1a;
CREATE TABLE people (fname text,lname text
);CREATE FUNCTION full_name(people) RETURNS text AS $$SELECT $1.fname || &#39; &#39; || $1.lname;
$$ LANGUAGE SQL;-- (optional) add an index to speed up anticipated query
CREATE INDEX people_full_name_idx ON peopleUSING GIN (to_tsvector(&#39;english&#39;, full_name(people)));
在计算列上的全文本搜索&#xff1a;
GET /people?full_name&#61;fts.Beckett HTTP/1.1
如前所述&#xff0c;默认情况下&#xff0c;计算列不会出现在输出中。但是&#xff0c;您可以通过在垂直过滤select
参数中列出它们来包括它们&#xff1a;
GET /people?select&#61;*,full_name HTTP/1.1
重要
必须在公开的架构下创建计算列才能以这种方式使用。
PostgREST支持模式&#xff0c;表&#xff0c;列和值中的unicode。要访问具有Unicode名称的表&#xff0c;请使用百分比编码。
要求此&#xff1a;
GET /موارد HTTP/1.1
做这个&#xff1a;
GET /%D9%85%D9%88%D8%A7%D8%B1%D8%AF HTTP/1.1
您可以通过以下方式对表/列中的空格进行编码%20
&#xff1a;
GET /Order%20Items?Unit%20Price&#61;lt.200 HTTP/1.1
如果过滤器包括PostgREST保留字符&#xff08;,
&#xff0c;.
&#xff0c;:
&#xff0c;()
&#xff09;你必须围绕这些百分比编码双引号%22
进行正确的处理。
这里Hebdon,John
和Williams,Mary
是值。
GET /employees?name&#61;in.(%22Hebdon,John%22,%22Williams,Mary%22) HTTP/1.1
这information.cpe
是列名。
GET /vulnerabilities?%22information.cpe%22&#61;like.*MS* HTTP/1.1
注意
一些http库可能会自动编码URL&#xff08;例如axios
&#xff09;。在这种情况下&#xff0c;您应该""
直接使用双引号 而不是%22
。
保留字order
对响应行进行重新排序。它使用逗号分隔的列和方向列表&#xff1a;
GET /people?order&#61;age.desc,height.asc HTTP/1.1
如果未指定方向&#xff0c;则默认为升序&#xff1a;
GET /people?order&#61;age HTTP/1.1
如果您关心null的排序位置&#xff0c;请先添加nullsfirst或nullslast&#xff1a;
GET /people?order&#61;age.nullsfirst HTTP/1.1
GET /people?order&#61;age.desc.nullslast HTTP/1.1
您也可以使用“ 计算列”对结果进行排序&#xff0c;即使计算列不会出现在输出中。
PostgREST使用HTTP范围标头来描述结果的大小。每个响应均包含当前范围以及&#xff08;如果要求&#xff09;结果总数&#xff1a;
HTTP/1.1 200 OK
Range-Unit: items
Content-Range: 0-14/*
这里返回零到十四的项目。该信息在每个响应中都可用&#xff0c;并且可以帮助您在客户端上呈现分页控件。这是一个符合RFC7233的解决方案&#xff0c;可以使响应JSON更干净。
应用限制行和偏移行的方式有两种&#xff1a;通过请求标头或查询参数。使用标题时&#xff0c;请指定所需的行范围。该请求将获得前20个人。
GET /people HTTP/1.1
Range-Unit: items
Range: 0-19
请注意&#xff0c;如果无法满足您的请求&#xff0c;服务器的响应可能会更少&#xff1a;
HTTP/1.1 200 OK
Range-Unit: items
Content-Range: 0-17/*
您也可以要求无限制范围的开放范围&#xff0c;例如。Range: 10-
请求限制或偏移量的另一种方法是使用查询参数。例如
GET /people?limit&#61;15&offset&#61;30 HTTP/1.1
此方法对于嵌入式资源也很有用&#xff0c;我们将在另一部分中介绍。即使您使用查询参数来限制查询&#xff0c;服务器也会始终以范围标头作为响应。
为了获得表或视图的总大小&#xff08;例如在分页控件中呈现最后一个页面链接时&#xff09;&#xff0c;请在请求标头中指定您的首选项&#xff1a;
GET /bigtable HTTP/1.1
Range-Unit: items
Range: 0-24
Prefer: count&#61;exact
请注意&#xff0c;表越大&#xff0c;查询在数据库中运行的速度就越慢。服务器将响应所选范围和总计
HTTP/1.1 206 Partial Content
Range-Unit: items
Content-Range: 0-24/3573458
PostgREST使用适当的HTTP内容协商&#xff08;RFC7231&#xff09;来传递所需的资源表示形式。也就是说&#xff0c;相同的API终结点可以根据客户端请求以JSON或CSV等不同格式进行响应。
使用接受请求标头为响应指定可接受的格式&#xff1a;
GET /people HTTP/1.1
Accept: application/json
当前的可能性是
对于API端点和根目录上的OpenAPI&#xff0c;服务器将默认为JSON。
默认情况下&#xff0c;即使只有一项&#xff0c;PostgREST也会以数组形式返回所有JSON结果。例如&#xff0c;要求/items?id&#61;eq.1
退货
[{ "id": 1 }
]
这对于客户端代码可能很不方便。要将第一个结果作为数组未包含的对象返回&#xff0c;请指定vnd.pgrst.object
为Accept
标头的一部分
GET /items?id&#61;eq.1 HTTP/1.1
Accept: application/vnd.pgrst.object&#43;json
这返回
{ "id": 1 }
当请求单个响应但未找到任何条目时&#xff0c;服务器将以错误消息和406 Not Acceptable状态码响应&#xff0c;而不是通常的空数组和200状态&#xff1a;
{"message": "JSON object requested, multiple (or no) rows returned","details": "Results contain 0 rows, application/vnd.pgrst.object&#43;json requires 1 row"
}
注意
许多API使用特殊的嵌套URL约定&#xff08;例如/ stories vs / stories / 1&#xff09;来区分多个资源和单个资源。为什么我们使用/stories?id&#61;eq.1&#xff1f;答案是因为单数资源&#xff08;对我们而言&#xff09;是由主键确定的行&#xff0c;并且主键可以是复合键&#xff08;意思是在多个列上定义&#xff09;。较为熟悉的嵌套url仅考虑简单且压倒性的数字主键的简并情况。这些所谓的人工密钥通常由对象关系映射库自动引入。
诚然&#xff0c;PostgREST可以检测到构成主键的所有列上是否存在相等条件&#xff0c;并自动将其转换为单数。但是&#xff0c;这可能会导致格式发生令人惊讶的变化&#xff0c;仅通过过滤额外的列就可以打破不必要的客户端代码。相反&#xff0c;我们允许手动指定单数或复数&#xff0c;以使该选择与URL格式脱钩。
除了为每个表和视图提供RESTful路由外&#xff0c;PostgREST还允许将相关资源一起包含在单个API调用中。这减少了对多个API请求的需求。服务器使用外键确定可以一起返回哪些表和视图。例如&#xff0c;考虑电影及其奖项的数据库&#xff1a;
重要
PostgREST需要FOREIGN KEY约束才能进行资源嵌入。
如上文“ 垂直过滤&#xff08;列&#xff09;”所示&#xff0c;我们可以要求所有电影的标题&#xff0c;如下所示&#xff1a;
GET /films?select&#61;title HTTP/1.1
这可能会返回类似
[{ "title": "Workers Leaving The Lumière Factory In Lyon" },{ "title": "The Dickson Experimental Sound Film" },{ "title": "The Haunted Castle" }
]
但是&#xff0c;由于电影和导演之间存在外键约束&#xff0c;因此我们可以要求包含以下信息&#xff1a;
GET /films?select&#61;title,directors(id,last_name) HTTP/1.1
哪个会回来
[{ "title": "Workers Leaving The Lumière Factory In Lyon","directors": {"id": 2,"last_name": "Lumière"}},{ "title": "The Dickson Experimental Sound Film","directors": {"id": 1,"last_name": "Dickson"}},{ "title": "The Haunted Castle","directors": {"id": 3,"last_name": "Méliès"}}
]
在此示例中&#xff0c;由于该关系是前向关系&#xff0c;因此只有一位导演与电影关联。由于表名是复数形式&#xff0c;因此最好改为单数形式。表名别名可以实现以下目的&#xff1a;
GET /films?select&#61;title,director:directors(id,last_name) HTTP/1.1
重要
每当数据库模式中的FOREIGN KEY约束发生更改时&#xff0c;都必须刷新PostgREST的模式缓存&#xff0c;以使“资源嵌入”正常工作。请参阅“ 模式重新加载 ”部分。
PostgREST还可以检测通过联接表进行的关系。因此&#xff0c;您可以请求电影演员&#xff08;在这种情况下&#xff0c;通过角色来查找信息&#xff09;。您还可以反转包容的方向&#xff0c;要求所有导演&#xff0c;包括其电影列表&#xff1a;
GET /directors?select&#61;films(title,year) HTTP/1.1
嵌入式资源的形状可以与其顶级资源相似。为此&#xff0c;请在查询参数前面加上嵌入式资源的名称。例如&#xff0c;要订购每部电影中的演员&#xff1a;
GET /films?select&#61;*,actors(*)&actors.order&#61;last_name,first_name HTTP/1.1
这个排序在每一部电影的演员名单&#xff0c;但并没有改变电影本身的顺序。要过滤每部电影返回的角色&#xff1a;
GET /films?select&#61;*,roles(*)&roles.character&#61;in.(Chico,Harpo,Groucho) HTTP/1.1
再一次&#xff0c;这将角色包括在某些角色中&#xff0c;但不以任何方式过滤电影。没有这些字符的电影将与空字符列表一起包括在内。
一个or
过滤器可以用于类似的操作&#xff1a;
GET /films?select&#61;*,roles(*)&roles.or&#61;(character.eq.Gummo,character.eq.Zeppo) HTTP/1.1
限制和偏移操作是可能的&#xff1a;
GET /films?select&#61;*,actors(*)&actors.limit&#61;10&actors.offset&#61;2 HTTP/1.1
可以为嵌入式资源添加别名&#xff0c;并可以对这些别名应用过滤器&#xff1a;
GET /films?select&#61;*,90_comps:competitions(name),91_comps:competitions(name)&90_comps.year&#61;eq.1990&91_comps.year&#61;eq.1991 HTTP/1.1
如果视图包含在源表中定义了外键的列&#xff0c;则可以嵌入视图。
作为示例&#xff0c;让我们nominations_view
基于提名表创建一个名为的视图。
CREATE VIEW nominations_view AS
SELECTrank, competition_id, film_id
FROMnominations;
由于其中包含competition_id
和film_id
&#xff0c;并且每个人的源表中都有一个外键&#xff0c;因此我们可以嵌入竞赛和电影&#xff1a;
GET /nominations_view?select&#61;rank,competitions(name,year),films(title)&rank&#61;eq.5 HTTP/1.1
也可以嵌入物化视图。
警告
不能保证所有视图都是可嵌入的。特别是&#xff0c;包含UNION的视图将不可嵌入。
为什么&#xff1f;PostgREST通过查询和解析pg_rewrite在视图中检测源表外键。根据视图的复杂性&#xff0c;这可能会失败。
如果您的视图无法嵌入&#xff0c;请报告问题&#xff0c;以便我们继续改进外键检测。
将来&#xff0c;我们将提供一种方法来手动指定视图源外键以解决此限制。
重要
如果视图定义发生更改&#xff0c;则必须刷新PostgREST的架构缓存才能使其正常工作。请参阅“ 模式重新加载 ”部分。
PostgREST URL语法限制了客户端可以执行的查询类型。它可以防止任意的&#xff0c;可能构造不良的和缓慢的客户端查询。这对服务质量有好处&#xff0c;但是意味着数据库管理员必须创建自定义视图和存储过程以提供更丰富的端点。自定义端点的最常见原因是
fts
过滤器更复杂的全文本搜索可以在/rpc
前缀下访问API公开的数据库模式中的每个存储过程。API端点支持POST&#xff08;在某些情况下为GET&#xff09;来执行该功能。
POST /rpc/function_name HTTP/1.1
这些函数可以执行PostgreSQL允许的任何操作&#xff08;读取数据&#xff0c;修改数据&#xff0c;甚至进行DDL操作&#xff09;。
要在API调用中提供参数&#xff0c;请在请求有效负载中包含一个JSON对象&#xff0c;并且该对象的每个键/值都将成为参数。
例如&#xff0c;假设我们已经在数据库中创建了此函数。
CREATE FUNCTION add_them(a integer, b integer)
RETURNS integer AS $$SELECT a &#43; b;
$$ LANGUAGE SQL IMMUTABLE;
客户端可以通过发布一个对象来调用它
POST /rpc/add_them HTTP/1.1{ "a": 1, "b": 2 }3
重要
每当您创建或更改函数时&#xff0c;都必须刷新PostgREST的架构缓存。请参阅“ 模式重新加载 ”部分。
如果未刷新架构缓存&#xff0c;则PostgREST将假定text
为函数参数的默认类型。这可能会导致获得错误响应&#xff0c;例如&#xff1a;
{"hint":"No function matches the given name and argument types. You might need to add explicit type casts.","details":null,"code":"42883","message":"function test.add_them(a &#61;> text, b &#61;> text) does not exist"
}
您还可以通过发送带有请求的标头来调用采用json类型的单个参数的函数。这样&#xff0c;JSON请求主体将用作单个参数。Prefer: params&#61;single-object
CREATE FUNCTION mult_them(param json) RETURNS int AS $$SELECT (param->>&#39;x&#39;)::int * (param->>&#39;y&#39;)::int
$$ LANGUAGE SQL;
POST /rpc/mult_them HTTP/1.1
Prefer: params&#61;single-object{ "x": 4, "y": 2 }8
必须使用命名参数声明过程&#xff0c;过程声明如下&#xff1a;
CREATE FUNCTION non_named_args(integer, text, integer) ...
无法在PostgREST中调用&#xff0c;因为我们在内部使用命名符号。
请注意&#xff0c;PostgreSQL会将标识符名称转换为小写&#xff0c;除非您用如下方式引用它们&#xff1a;
CREATE FUNCTION "someFunc"("someParam" text) ...
PostgreSQL具有四种程序语言&#xff0c;它们是核心发行版的一部分&#xff1a;PL / pgSQL&#xff0c;PL / Tcl&#xff0c;PL / Perl和PL / Python。还有许多其他程序语言作为附加扩展分发。同样&#xff0c;纯SQL可以用于编写函数&#xff08;如上面的示例所示&#xff09;。
注意
对于PostgreSQL 10之前的版本&#xff0c;要传递PostgreSQL本机数组&#xff0c;您需要将其引用为字符串&#xff1a;
POST /rpc/native_array_func HTTP/1.1{ "arg": "{1,2,3}" }
在这些版本中&#xff0c;我们建议使用json类型的函数参数来接受来自客户端的数组&#xff1a;
POST /rpc/json_array_func HTTP/1.1{ "arg": [1,2,3] }
从PostgreSQL 10开始&#xff0c;来自客户端的json数组通常会映射到PostgreSQL本机数组。
注意
为什么使用/ rpc前缀&#xff1f;原因之一是避免视图和过程之间的名称冲突。它还有助于向API使用者强调这些功能不是正常的烦人的事情。这些功能可能具有任意和令人惊讶的行为&#xff0c;而不是用户期望从其他途径获得的标准“后期创建资源”。
PostgreSQL中标有stable
或易失immutable
性的过程只能读取&#xff0c;不能修改数据库&#xff0c;而PostgREST在与只读副本兼容的只读事务中执行它们。如果需要&#xff0c;可以使用HTTP GET动词调用稳定和不可变的函数。
注意
波动性标志是有关功能行为的承诺。PostgreSQL将允许您将修改数据库的功能标记为immutable/stable
无故障。但是&#xff0c;通过PostgREST调用时&#xff0c;该函数将失败&#xff0c;因为它是在只读事务中执行该函数。
因为add_them
被声明为IMMUTABLE&#xff0c;所以我们可以用GET请求交替调用该函数&#xff1a;
GET /rpc/add_them?a&#61;1&b&#61;2 HTTP/1.1
函数参数名称在POST情况下与JSON对象键匹配&#xff0c;对于GET情况&#xff0c;它们与查询参数匹配?a&#61;1&b&#61;2
。
PostgREST将检测该函数是标量的还是表值的&#xff0c;并将相应地调整响应格式&#xff1a;
GET /rpc/add_them?a&#61;1&b&#61;2 HTTP/1.13
GET /rpc/best_films_2017 HTTP/1.1[{ "title": "Okja", "rating": 7.4},{ "title": "Call me by your name", "rating": 8},{ "title": "Blade Runner 2049", "rating": 8.1}
]
类似于Bulk Insert&#xff0c;可以批量调用函数。
POST /rpc/add_them HTTP/1.1
Content-Type: application/json[{"a": 1, "b": 2},{"a": 3, "b": 4}
]
结果&#xff1a;
[ 3, 7 ]
也可以在函数调用中指定列。
返回表类型响应的函数可以使用与用于表和视图的过滤器相同的过滤器来整形&#xff1a;
CREATE FUNCTION best_films_2017() RETURNS SETOF films ..
GET /rpc/best_films_2017?select&#61;title,director:directors(*) HTTP/1.1
GET /rpc/best_films_2017?rating&#61;gt.8&order&#61;title.desc HTTP/1.1
默认情况下&#xff0c;函数以调用它的用户的特权执行。这意味着用户必须具有所有权限才能执行该过程执行的操作。
另一种选择是使用该选项定义功能。然后&#xff0c;将只进行一次权限检查&#xff0c;即调用该功能的权限&#xff0c;并且该功能中的操作将拥有拥有该功能本身的用户的权限。有关更多详细信息&#xff0c;请参见PostgreSQL文档。SECURITY DEFINER
警告
与表/视图不同&#xff0c;函数特权用作黑名单&#xff0c;因此默认情况下&#xff0c;它们对于所有角色都是可执行的。您可以通过撤销功能的PUBLIC特权&#xff0c;然后将特权授予特定角色来解决此问题&#xff1a;
REVOKE ALL PRIVILEGES ON FUNCTION private_func() FROM PUBLIC;
GRANT EXECUTE ON FUNCTION private_func() TO a_role;
另外&#xff0c;为了避免执行REVOKE
所有功能&#xff0c;您可以默认使用以下方式启用此行为&#xff1a;
ALTER DEFAULT PRIVILEGES REVOKE EXECUTE ON FUNCTIONS FROM PUBLIC;
有关更多详细信息&#xff0c;请参见PostgreSQL alter default特权。
您可以使用不同数量的参数调用重载函数。
CREATE FUNCTION rental_duration(customer_id integer) ..CREATE FUNCTION rental_duration(customer_id integer, from_date date) ..
GET /rpc/rental_duration?customer_id&#61;232 HTTP/1.1
GET /rpc/rental_duration?customer_id&#61;232&from_date&#61;2018-07-01 HTTP/1.1
通过读取每个请求的PostgREST设置的GUC变量&#xff0c;存储过程可以访问请求标头&#xff0c;COOKIE和jwt声明。它们被命名为request.header.XYZ
&#xff0c;request.COOKIE.XYZ
和request.jwt.claim.XYZ
。
-- To read the value of the Origin request header:
SELECT current_setting(&#39;request.header.origin&#39;, true);
-- To read the value of sessionId in a COOKIE:
SELECT current_setting(&#39;request.COOKIE.sessionId&#39;, true);
-- To read the value of the email claim in a jwt:
SELECT current_setting(&#39;request.jwt.claim.email&#39;, true);
注意
request.jwt.claim.role
缺省为db-anon-role的值。
PostgREST读取response.headers
SQL变量以将额外的标头添加到HTTP响应。存储过程可以修改此变量。例如&#xff0c;此语句将在响应中添加缓存头&#xff1a;
-- tell client to cache response for two daysSET LOCAL "response.headers" &#61;&#39;[{"Cache-Control": "public"}, {"Cache-Control": "max-age&#61;259200"}]&#39;;
请注意&#xff0c;该变量应设置为单键对象数组&#xff0c;而不是单个多键对象。这是因为设置多个值时&#xff0c;必须重复标头&#xff08;例如Cache-Control
或&#xff09;Set-COOKIE
&#xff0c;并且对象不允许重复的键。
通过引发SQL异常&#xff0c;存储过程可以返回非200 HTTP状态代码。例如&#xff0c;这是一个伪函数&#xff0c;总是会返回错误&#xff1a;
CREATE OR REPLACE FUNCTION just_fail() RETURNS voidLANGUAGE plpgsqlAS $$
BEGINRAISE EXCEPTION &#39;I refuse!&#39;USING DETAIL &#61; &#39;Pretty simple&#39;,HINT &#61; &#39;There is nothing you can do.&#39;;
END
$$;
调用该函数将返回带有正文的HTTP 400
{"message":"I refuse!","details":"Pretty simple","hint":"There is nothing you can do.","code":"P0001"
}
定制HTTP状态代码的一种方法是根据PostgREST 错误到状态代码的映射引发特定异常。例如&#xff0c;将使用HTTP 401/403进行响应。RAISE insufficient_privilege
为了更好地控制HTTP状态代码&#xff0c;请引发PTxyz
类型的异常。例如&#xff0c;使用HTTP 402进行响应&#xff0c;请举起&#39;PT402&#39;&#xff1a;
RAISE sqlstate &#39;PT402&#39; usingmessage &#61; &#39;Payment Required&#39;,detail &#61; &#39;Quota exceeded&#39;,hint &#61; &#39;Upgrade your plan&#39;;
返回值&#xff1a;
HTTP/1.1 402 Payment Required
Content-Type: application/json; charset&#61;utf-8{"hint":"Upgrade your plan","details":"Quota exceeded"}
可以根据请求者的数据库角色的权限&#xff0c;通过API修改所有表和自动更新的视图。
要在数据库表中创建行&#xff0c;请发布一个JSON对象&#xff0c;该对象的键是要创建的列的名称。适用时&#xff0c;缺少的属性将设置为默认值。
POST /table_name HTTP/1.1{ "col1": "value1", "col2": "value2" }
该响应将包含一个Location
标题&#xff0c;该标题描述了在哪里可以找到新对象。如果表是只写的&#xff0c;那么构造Location标头将导致权限错误。要将项目成功插入到只写表中&#xff0c;您需要通过包含request标头来抑制Location响应标头。Prefer: return&#61;minimal
在频谱的另一端&#xff0c;可以通过包含标头将完整的创建对象返回给您的请求响应。这样&#xff0c;您就不必进行其他HTTP调用来发现可能已在服务器端填充的属性。您也可以将标准垂直过滤&#xff08;列&#xff09;应用于这些结果。Prefer: return&#61;representation
URL编码的有效载荷可以使用来发布。Content-Type: application/x-www-form-urlencoded
POST /people HTTP/1.1
Content-Type: application/x-www-form-urlencodedname&#61;John&#43;Doe&age&#61;50&weight&#61;80
注意
插入行时&#xff0c;您必须发布一个JSON对象&#xff0c;而不是用引号引起来的JSON。
Yes
{ "a": 1, "b": 2 }No
"{ \"a\": 1, \"b\": 2 }"
如果您不小心&#xff0c;某些Javascript库会错误地发布数据。为了获得最佳结果&#xff0c;请尝试为PostgREST构建的客户端库之一。
要更新表中的一行或多行&#xff0c;请使用PATCH动词。使用水平过滤&#xff08;行&#xff09;来指定要更新的记录。这是一个示例查询&#xff0c;将category
特定年龄以下的所有人的列设置为child。
PATCH /people?age&#61;lt.13 HTTP/1.1{ "category": "child" }
更新还支持加垂直滤波&#xff08;列&#xff09;。Prefer: return&#61;representation
警告
当心意外更新表中的每一行。要了解如何防止这种情况&#xff0c;请参阅“ 阻止全表操作”。
警告
使用PostgREST可能无法在具有复杂规则的VIEW上插入。建议您使用触发器而不是RULEs。如果要继续使用RULE&#xff0c;一种解决方法是将VIEW插入包装在存储过程中&#xff0c;然后通过“ 存储过程”界面调用它。
批量插入的工作原理与单行插入完全相同&#xff0c;不同之处在于&#xff0c;您可以提供具有统一键的对象的JSON数组或CSV格式的行。这不仅使所需的HTTP请求最小化&#xff0c;而且在后端使用单个INSERT语句以提高效率。请注意&#xff0c;使用CSV需要较少的服务器解析&#xff0c;并且速度更快。
要批量插入CSV&#xff0c;只需将发布到的表格路由中&#xff0c;并在第一行中包含列名即可。例如Content-Type: text/csv
POST /people HTTP/1.1
Content-Type: text/csvname,age,height
J Doe,62,70
Jonas,10,55
空字段&#xff08;,,
&#xff09;强制为空字符串&#xff0c;保留字NULL
映射为SQL空值。请注意&#xff0c;列名和逗号之间不应有空格。
要批量插入JSON&#xff0c;请发布具有所有匹配键的对象数组
POST /people HTTP/1.1
Content-Type: application/json[{ "name": "J Doe", "age": 62, "height": 70 },{ "name": "Janus", "age": 10, "height": 55 }
]
通过使用columns
查询参数&#xff0c;可以指定将要插入/更新的有效负载密钥&#xff0c;而忽略其余的有效负载。
POST /datasets?columns&#61;source,publication_date,figure HTTP/1.1
Content-Type: application/json{"source": "Natural Disaster Prevention and Control","publication_date": "2015-09-11","figure": 1100,"location": "...","comment": "...","extra": "...","stuff": "..."
}
在这种情况下&#xff0c;将仅插入source&#xff0c;publication_date和Figure。其余JSON键将被忽略。
使用此方法还具有提高批量插入效率的副作用&#xff0c;因为PostgREST不会处理JSON&#xff0c;而是将其直接发送到PostgreSQL。
您可以使用POST
和标头制作UPSERT &#xff1a;Prefer: resolution&#61;merge-duplicates
POST /employees HTTP/1.1
Prefer: resolution&#61;merge-duplicates[{ "id": 1, "name": "Old employee 1", "salary": 30000 },{ "id": 2, "name": "Old employee 2", "salary": 42000 },{ "id": 3, "name": "New employee 3", "salary": 50000 }
]
UPSERT基于主键列进行操作&#xff0c;您必须指定所有这些键。您还可以选择使用忽略重复项。当主键是自然键时&#xff0c;UPSERT效果最好&#xff0c;但是如果主键是替代键&#xff0c;则还可以使用它&#xff08;例如&#xff1a;“ id串行主键”&#xff09;。有关更多详细信息&#xff0c;请阅读此问题。Prefer: resolution&#61;ignore-duplicates
重要
创建表或更改其主键后&#xff0c;必须刷新PostgREST模式缓存以使UPSERT正常工作。要了解如何刷新缓存&#xff0c;请参阅Schema Reloading。
可以通过以下方式使用PUT
和过滤主键列来完成单行UPSERT eq
&#xff1a;
PUT /employees?id&#61;eq.4 HTTP/1.1{ "id": 4, "name": "Sara B.", "salary": 60000 }
必须在请求正文中指定所有列&#xff0c;包括主键列。
注意
该功能仅从PostgreSQL 9.5开始可用&#xff0c;因为它使用了ON CONFLICT子句。
要删除表中的行&#xff0c;请使用DELETE动词加上“ 水平过滤&#xff08;行&#xff09;”。例如删除不活动的用户&#xff1a;
DELETE /user?active&#61;is.false HTTP/1.1
警告
当心意外删除表中的所有行。要了解如何防止这种情况&#xff0c;请参阅“ 阻止全表操作”。
如果要从一bytea
列返回原始二进制数据&#xff0c;则必须指定application/octet-stream
作为Accept
标题的一部分&#xff0c;然后选择一个列?select&#61;bin_data
。
GET /items?select&#61;bin_data&id&#61;eq.1 HTTP/1.1
Accept: application/octet-stream
您还可以在调用存储过程时请求二进制输出&#xff0c;由于它们可以返回标量值&#xff0c;因此select
在这种情况下您不必强制使用。
CREATE FUNCTION closest_point(..) RETURNS bytea ..
POST /rpc/closest_point HTTP/1.1
Accept: application/octet-stream
如果存储过程返回非标量值&#xff0c;则需要执行select
与GET二进制输出相同的方法。
CREATE FUNCTION overlapping_regions(..) RETURNS SETOF TABLE(geom_twkb bytea, ..) ..
POST /rpc/overlapping_regions?select&#61;geom_twkb HTTP/1.1
Accept: application/octet-stream
注意
如果将返回多于一行&#xff0c;则二进制结果将被串联&#xff0c;并且没有定界符。
您可以text
使用来从列中获取原始输出。Accept: text/plain
GET /workers?select&#61;custom_psv_format HTTP/1.1
Accept: text/plain09310817|JOHN|DOE|15/04/88|
42152780|FRED|BLOGGS|20/02/85|
43006541|OTTO|NORMALVERBRAUCHER|01/07/90|
02452492|ERIKA|MUSTERMANN|11/01/80|
这遵循与Binary Output相同的规则。
PostgREST托管的每个API 都会在根路径上自动提供完整的OpenAPI描述。这提供了所有端点&#xff08;表&#xff0c;外部表&#xff0c;视图&#xff0c;函数&#xff09;的列表&#xff0c;以及受支持的HTTP动词和示例有效负载。为了进行额外的自定义&#xff0c;OpenAPI输出包含任何数据库对象上每个SQL注释的“描述”字段。例如&#xff0c;
COMMENT ON SCHEMA mammals IS&#39;A warm-blooded vertebrate animal of a class that is distinguished by the secretion of milk by females for the nourishment of the young&#39;;COMMENT ON TABLE monotremes IS&#39;Freakish mammals lay the best eggs for breakfast&#39;;COMMENT ON COLUMN monotremes.has_venomous_claw IS&#39;Sometimes breakfast is not worth it&#39;;
这些不良注释将在info.description
&#xff0c;definitions.monotremes.description
和中显示为生成的JSON definitions.monotremes.properties.has_venomous_claw.description
。
同样&#xff0c;如果您希望生成一个summary
字段&#xff0c;则可以通过多行注释来做到这一点&#xff0c;summary
它将是第一行以及其后description
的行&#xff1a;
COMMENT ON TABLE entities IS$$Entities summaryEntities description thatspansmultiple lines$$;
您可以使用Swagger UI之类的工具根据说明创建漂亮的文档&#xff0c;并托管基于Web的交互式仪表板。该仪表板允许开发人员针对实时的PostgREST服务器发出请求&#xff0c;并提供有关请求标头和示例请求正文的指南。
重要
随着架构在运行的服务器下更改&#xff0c;OpenAPI信息可能会过时。要了解如何刷新缓存&#xff0c;请参阅Schema Reloading。
PostgREST将PostgreSQL错误代码转换为HTTP状态&#xff0c;如下所示&#xff1a;
PostgreSQL error code(s) | HTTP status | Error description |
---|---|---|
08* | 503 | pg connection err |
09* | 500 | triggered action exception |
0L* | 403 | invalid grantor |
0P* | 403 | invalid role specification |
23503 | 409 | foreign key violation |
23505 | 409 | uniqueness violation |
25* | 500 | invalid transaction state |
28* | 403 | invalid auth specification |
2D* | 500 | invalid transaction termination |
38* | 500 | external routine exception |
39* | 500 | external routine invocation |
3B* | 500 | savepoint exception |
40* | 500 | transaction rollback |
53* | 503 | insufficient resources |
54* | 413 | too complex |
55* | 500 | obj not in prerequisite state |
57* | 500 | operator intervention |
58* | 500 | system error |
F0* | 500 | conf file error |
HV* | 500 | foreign data wrapper error |
P0001 | 400 | default code for “raise” |
P0* | 500 | PL/pgSQL error |
XX* | 500 | internal error |
42883 | 404 | undefined function |
42P01 | 404 | undefined table |
42501 | if authenticated 403, else 401 | insufficient privileges |
other | 400 |
翻译原文&#xff1a;http://postgrest.org/en/v6.0/api.html#operators