Return Location header only when using Prefer: return=header-only
This commit is contained in:
@@ -71,6 +71,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
+ For migrating, clients must be updated to the embedding form of `/view?select=*,other_view!column(*)`.
|
+ For migrating, clients must be updated to the embedding form of `/view?select=*,other_view!column(*)`.
|
||||||
- #1959, A full table PATCH(without filters) is now restricted, it requires a `limit` parameter - @steve-chavez
|
- #1959, A full table PATCH(without filters) is now restricted, it requires a `limit` parameter - @steve-chavez
|
||||||
+ A `PATCH /tbl` will now result in 0 rows updated, unless `PATCH /tbl?limit=10&order=<pkcol>` is done
|
+ A `PATCH /tbl` will now result in 0 rows updated, unless `PATCH /tbl?limit=10&order=<pkcol>` is done
|
||||||
|
- #2312, Using `Prefer: return=representation` no longer returns a `Location` header - @laurenceisla
|
||||||
|
|
||||||
## [9.0.1] - 2022-06-03
|
## [9.0.1] - 2022-06-03
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ createWriteStatement selectQuery mutateQuery wantSingle isInsert asCsv asGeoJson
|
|||||||
"FROM (" <> selectF <> ") _postgrest_t"
|
"FROM (" <> selectF <> ") _postgrest_t"
|
||||||
|
|
||||||
locF =
|
locF =
|
||||||
if isInsert && rep /= None
|
if isInsert && rep == HeadersOnly
|
||||||
then BS.unwords [
|
then BS.unwords [
|
||||||
"CASE WHEN pg_catalog.count(_postgrest_t) = 1",
|
"CASE WHEN pg_catalog.count(_postgrest_t) = 1",
|
||||||
"THEN coalesce(" <> locationF pKeys <> ", " <> noLocationF <> ")",
|
"THEN coalesce(" <> locationF pKeys <> ", " <> noLocationF <> ")",
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ instance ToAppliedHeader PreferResolution
|
|||||||
--
|
--
|
||||||
-- From https://tools.ietf.org/html/rfc7240#section-4.2
|
-- From https://tools.ietf.org/html/rfc7240#section-4.2
|
||||||
data PreferRepresentation
|
data PreferRepresentation
|
||||||
= Full -- ^ Return the body plus the Location header(in case of POST).
|
= Full -- ^ Return the body.
|
||||||
| HeadersOnly -- ^ Return the Location header(in case of POST). This needs a SELECT privilege on the pk.
|
| HeadersOnly -- ^ Return the Location header(in case of POST). This needs a SELECT privilege on the pk.
|
||||||
| None -- ^ Return nothing from the mutated data.
|
| None -- ^ Return nothing from the mutated data.
|
||||||
deriving Eq
|
deriving Eq
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ spec actualPgVersion = do
|
|||||||
[json|{"id":6,"name":"New Project","client_id":2}|] `shouldRespondWith` [json|[{"id":6,"name":"New Project","clients":{"id":2,"name":"Apple"}}]|]
|
[json|{"id":6,"name":"New Project","client_id":2}|] `shouldRespondWith` [json|[{"id":6,"name":"New Project","clients":{"id":2,"name":"Apple"}}]|]
|
||||||
{ matchStatus = 201
|
{ matchStatus = 201
|
||||||
, matchHeaders = [ matchContentTypeJson
|
, matchHeaders = [ matchContentTypeJson
|
||||||
, "Location" <:> "/projects?id=eq.6"
|
, matchHeaderAbsent hLocation
|
||||||
, "Content-Range" <:> "*/1" ]
|
, "Content-Range" <:> "*/1" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ spec actualPgVersion = do
|
|||||||
[json|[{"pId":"7","pName":"New Project","cId":"2"}]|]
|
[json|[{"pId":"7","pName":"New Project","cId":"2"}]|]
|
||||||
{ matchStatus = 201
|
{ matchStatus = 201
|
||||||
, matchHeaders = [ matchContentTypeJson
|
, matchHeaders = [ matchContentTypeJson
|
||||||
, "Location" <:> "/projects?id=eq.7"
|
, matchHeaderAbsent hLocation
|
||||||
, "Content-Range" <:> "*/*" ]
|
, "Content-Range" <:> "*/*" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ spec actualPgVersion = do
|
|||||||
[json|[{"name":"New Project","client_id":2}]|]
|
[json|[{"name":"New Project","client_id":2}]|]
|
||||||
{ matchStatus = 201
|
{ matchStatus = 201
|
||||||
, matchHeaders = [ matchContentTypeJson
|
, matchHeaders = [ matchContentTypeJson
|
||||||
, "Location" <:> "/projects?id=eq.10"
|
, matchHeaderAbsent hLocation
|
||||||
, "Content-Range" <:> "*/*" ]
|
, "Content-Range" <:> "*/*" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ spec actualPgVersion = do
|
|||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json|[ { "k1":12, "k2":"Rock & R+ll", "extra": null } ]|]
|
[json|[ { "k1":12, "k2":"Rock & R+ll", "extra": null } ]|]
|
||||||
{ matchStatus = 201
|
{ matchStatus = 201
|
||||||
, matchHeaders = [ "Location" <:> "/compound_pk?k1=eq.12&k2=eq.Rock%20%26%20R%2Bll" ]
|
, matchHeaders = [ matchHeaderAbsent hLocation ]
|
||||||
}
|
}
|
||||||
|
|
||||||
context "with bulk insert" $
|
context "with bulk insert" $
|
||||||
@@ -436,6 +436,37 @@ spec actualPgVersion = do
|
|||||||
, matchHeaders = []
|
, matchHeaders = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context "with unicode values" $ do
|
||||||
|
it "succeeds and returns full representation" $
|
||||||
|
request methodPost "/simple_pk2?select=extra,k"
|
||||||
|
[("Prefer", "return=representation")]
|
||||||
|
[json| { "k":"圍棋", "extra":"¥" } |]
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[ { "k":"圍棋", "extra":"¥" } ]|]
|
||||||
|
{ matchStatus = 201 }
|
||||||
|
|
||||||
|
it "succeeds and returns usable location header" $ do
|
||||||
|
p <- request methodPost "/simple_pk2?select=extra,k"
|
||||||
|
[("Prefer", "tx=commit"), ("Prefer", "return=headers-only")]
|
||||||
|
[json| { "k":"圍棋", "extra":"¥" } |]
|
||||||
|
pure p `shouldRespondWith`
|
||||||
|
""
|
||||||
|
{ matchStatus = 201 }
|
||||||
|
|
||||||
|
Just location <- pure $ lookup hLocation $ simpleHeaders p
|
||||||
|
get location
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[ { "k":"圍棋", "extra":"¥" } ]|]
|
||||||
|
|
||||||
|
request methodDelete location
|
||||||
|
[("Prefer", "tx=commit")]
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
""
|
||||||
|
{ matchStatus = 204
|
||||||
|
, matchHeaders = [matchHeaderAbsent hContentType]
|
||||||
|
}
|
||||||
|
|
||||||
describe "CSV insert" $ do
|
describe "CSV insert" $ do
|
||||||
context "disparate csv types" $
|
context "disparate csv types" $
|
||||||
it "succeeds with multipart response" $ do
|
it "succeeds with multipart response" $ do
|
||||||
@@ -489,29 +520,6 @@ spec actualPgVersion = do
|
|||||||
, matchHeaders = [matchContentTypeJson]
|
, matchHeaders = [matchContentTypeJson]
|
||||||
}
|
}
|
||||||
|
|
||||||
context "with unicode values" $
|
|
||||||
it "succeeds and returns usable location header" $ do
|
|
||||||
p <- request methodPost "/simple_pk2?select=extra,k"
|
|
||||||
[("Prefer", "tx=commit"), ("Prefer", "return=representation")]
|
|
||||||
[json| { "k":"圍棋", "extra":"¥" } |]
|
|
||||||
pure p `shouldRespondWith`
|
|
||||||
[json|[ { "k":"圍棋", "extra":"¥" } ]|]
|
|
||||||
{ matchStatus = 201 }
|
|
||||||
|
|
||||||
Just location <- pure $ lookup hLocation $ simpleHeaders p
|
|
||||||
get location
|
|
||||||
`shouldRespondWith`
|
|
||||||
[json|[ { "k":"圍棋", "extra":"¥" } ]|]
|
|
||||||
|
|
||||||
request methodDelete location
|
|
||||||
[("Prefer", "tx=commit")]
|
|
||||||
""
|
|
||||||
`shouldRespondWith`
|
|
||||||
""
|
|
||||||
{ matchStatus = 204
|
|
||||||
, matchHeaders = [matchHeaderAbsent hContentType]
|
|
||||||
}
|
|
||||||
|
|
||||||
describe "Row level permission" $
|
describe "Row level permission" $
|
||||||
it "set user_id when inserting rows" $ do
|
it "set user_id when inserting rows" $ do
|
||||||
request methodPost "/authors_only"
|
request methodPost "/authors_only"
|
||||||
@@ -537,7 +545,7 @@ spec actualPgVersion = do
|
|||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json|[{"id":6,"name":"wot","parent_content":{"name":"wut"}}]|]
|
[json|[{"id":6,"name":"wot","parent_content":{"name":"wut"}}]|]
|
||||||
{ matchStatus = 201
|
{ matchStatus = 201
|
||||||
, matchHeaders = [ matchContentTypeJson , "Location" <:> "/web_content?id=eq.6" ]
|
, matchHeaders = [ matchContentTypeJson , matchHeaderAbsent hLocation ]
|
||||||
}
|
}
|
||||||
|
|
||||||
context "table with limited privileges" $ do
|
context "table with limited privileges" $ do
|
||||||
|
|||||||
Reference in New Issue
Block a user