Skip to content

Commit

Permalink
feat: Add explicit headers-only POST request using Prefer header
Browse files Browse the repository at this point in the history
Allows using header "Prefer=headers-only" explicitly to get a response with only a Location header.

BREAKING CHANGE: Change default for POST request from headers-only to minimal

Resolves #1656
  • Loading branch information
laurenceisla committed Apr 13, 2021
1 parent cd09cc6 commit 4b46c4e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 19 deletions.
9 changes: 4 additions & 5 deletions src/PostgREST/Request/ApiRequest.hs
Expand Up @@ -334,11 +334,10 @@ userApiRequest confSchemas rootSpec dbStructure req reqBody
split :: BS.ByteString -> [Text]
split = map T.strip . T.split (==',') . toS
representation
| hasPrefer (show Full) = Full
| hasPrefer (show None) = None
| otherwise = if action == ActionCreate
then HeadersOnly -- Assume the user wants the Location header(for POST) by default
else None
| hasPrefer (show Full) = Full
| hasPrefer (show None) = None
| hasPrefer (show HeadersOnly) = HeadersOnly
| otherwise = None
auth = fromMaybe "" $ lookupHeader hAuthorization
tokenStr = case T.split (== ' ') (toS auth) of
("Bearer" : t : _) -> t
Expand Down
2 changes: 1 addition & 1 deletion src/PostgREST/Request/Preferences.hs
Expand Up @@ -22,7 +22,7 @@ data PreferRepresentation
instance Show PreferRepresentation where
show Full = "return=representation"
show None = "return=minimal"
show HeadersOnly = mempty
show HeadersOnly = "return=headers-only"

data PreferParameters
= SingleObject -- ^ Pass all parameters as a single json object to a stored procedure
Expand Down
45 changes: 32 additions & 13 deletions test/Feature/InsertSpec.hs
Expand Up @@ -111,15 +111,23 @@ spec actualPgVersion = do
, "Content-Range" <:> "*/*" ]
}

context "requesting no representation" $
context "requesting headers only representation" $
it "should not throw and return location header when selecting without PK" $
request methodPost "/projects?select=name,client_id" []
request methodPost "/projects?select=name,client_id" [("Prefer", "return=headers-only")]
[json|{"id":11,"name":"New Project","client_id":2}|] `shouldRespondWith` ""
{ matchStatus = 201
, matchHeaders = [ "Location" <:> "/projects?id=eq.11"
, "Content-Range" <:> "*/*" ]
}

context "requesting no representation" $
it "should not throw and return no location header when selecting without PK" $
request methodPost "/projects?select=name,client_id" []
[json|{"id":12,"name":"New Project","client_id":2}|] `shouldRespondWith` ""
{ matchStatus = 201
, matchHeaders = [ matchHeaderAbsent hLocation ]
}

context "from an html form" $
it "accepts disparate json types" $ do
request methodPost "/menagerie"
Expand All @@ -140,7 +148,7 @@ spec actualPgVersion = do
`shouldRespondWith`
[json|""|]

post "/auto_incrementing_pk"
request methodPost "/auto_incrementing_pk" [("Prefer", "return=headers-only")]
[json| { "non_nullable_string":"not null"} |]
`shouldRespondWith`
""
Expand Down Expand Up @@ -508,13 +516,24 @@ spec actualPgVersion = do
""
{ matchStatus = 201 }

describe "Inserting into VIEWs" $
it "returns a location header" $
post "/compound_pk_view"
[json|{"k1":1,"k2":"test","extra":2}|]
`shouldRespondWith`
""
{ matchStatus = 201
, matchHeaders = [ "Location" <:> "/compound_pk_view?k1=eq.1&k2=eq.test"
, "Content-Range" <:> "*/*" ]
}
describe "Inserting into VIEWs" $ do
context "requesting no representation" $
it "succeeds with 201" $
post "/compound_pk_view"
[json|{"k1":1,"k2":"test","extra":2}|]
`shouldRespondWith`
""
{ matchStatus = 201
, matchHeaders = [ matchHeaderAbsent hLocation ]
}

context "requesting header only representation" $
it "returns a location header" $
request methodPost "/compound_pk_view" [("Prefer", "return=headers-only")]
[json|{"k1":1,"k2":"test","extra":2}|]
`shouldRespondWith`
""
{ matchStatus = 201
, matchHeaders = [ "Location" <:> "/compound_pk_view?k1=eq.1&k2=eq.test"
, "Content-Range" <:> "*/*" ]
}

0 comments on commit 4b46c4e

Please sign in to comment.