Skip to content

Commit

Permalink
fix: Return status code 200 when PATCHing without changing rows
Browse files Browse the repository at this point in the history
This partially reverts PostgREST#1257 / PostgREST#1272 / 5535317 where the 404 was introduced.

A 406 error is still returned when requesting a single object via accept header.

Returning an error when no rows are changed can be introduced through a different syntax again, see the discussion in PostgREST#2164.

Fixes PostgREST#2343

Signed-off-by: Wolfgang Walther <[email protected]>
  • Loading branch information
wolfgangwalther committed Oct 27, 2022
1 parent 9be6747 commit 38dd893
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #2458, Fix a regression with the location header when inserting into views with PKs from multiple tables - @wolfgangwalther
- #2356, Fix a regression in openapi output with mode follow-privileges - @wolfgangwalther
- #2283, Fix infinite recursion when loading schema cache with self-referencing view - @wolfgangwalther
- #2343, Return status code 200 for PATCH requests which don't affect any rows - @wolfgangwalther

### Deprecated

Expand Down
15 changes: 5 additions & 10 deletions src/PostgREST/Response.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import qualified Data.Aeson as JSON
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.HashMap.Strict as HM
import qualified Data.Set as S
import Data.Text.Read (decimal)
import qualified Network.HTTP.Types.Header as HTTP
import qualified Network.HTTP.Types.Status as HTTP
Expand Down Expand Up @@ -121,21 +120,17 @@ updateResponse ctxApiRequest@ApiRequest{..} resultSet = case resultSet of
RSStandard{..} -> do
let
response = gucResponse rsGucStatus rsGucHeaders
fullRepr = iPreferRepresentation == Full
updateIsNoOp = S.null iColumns
status
| rsQueryTotal == 0 && not updateIsNoOp = HTTP.status404
| fullRepr = HTTP.status200
| otherwise = HTTP.status204
contentRangeHeader =
RangeQuery.contentRangeH 0 (rsQueryTotal - 1) $
if shouldCount iPreferCount then Just rsQueryTotal else Nothing
headers = [contentRangeHeader]

if fullRepr then
response status (headers ++ contentTypeHeaders ctxApiRequest) (LBS.fromStrict rsBody)
if iPreferRepresentation == Full then
response HTTP.status200
(headers ++ contentTypeHeaders ctxApiRequest)
(LBS.fromStrict rsBody)
else
response status headers mempty
response HTTP.status204 headers mempty

RSPlan plan ->
Wai.responseLBS HTTP.status200 (contentTypeHeaders ctxApiRequest) $ LBS.fromStrict plan
Expand Down
18 changes: 9 additions & 9 deletions test/spec/Feature/Query/UpdateSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ spec = do
`shouldRespondWith` 404

context "on an empty table" $
it "indicates no records found to update by returning 404" $
it "succeeds with status code 204" $
request methodPatch "/empty_table" []
[json| { "extra":20 } |]
`shouldRespondWith`
""
{ matchStatus = 404,
{ matchStatus = 204,
matchHeaders = [matchHeaderAbsent hContentType]
}

Expand Down Expand Up @@ -71,14 +71,14 @@ spec = do
[("Prefer", "return=representation")] [json| { "id":999999 } |]
`shouldRespondWith` "[]"
{
matchStatus = 404,
matchStatus = 200,
matchHeaders = []
}

it "gives a 404 when no rows updated" $
it "returns status code 200 when no rows updated" $
request methodPatch "/items?id=eq.99999999" []
[json| { "id": 42 } |]
`shouldRespondWith` 404
`shouldRespondWith` 204

it "returns updated object as array when return=rep" $
request methodPatch "/items?id=eq.2"
Expand Down Expand Up @@ -137,13 +137,13 @@ spec = do
matchHeaders = [matchContentTypeJson, "Content-Range" <:> "0-0/*"]
}

it "indicates no records updated by returning 404" $
it "returns empty array when no rows updated and return=rep" $
request methodPatch
"/items?always_true=eq.false"
[("Prefer", "return=representation")]
[json| { id: 100 } |]
`shouldRespondWith` "[]"
{ matchStatus = 404,
{ matchStatus = 200,
matchHeaders = []
}

Expand Down Expand Up @@ -304,9 +304,9 @@ spec = do
`shouldRespondWith`
[json|[{"id": 1, "body": "Some real content", "owner": "postgrest_test_anonymous"}]|]

it "ignores json keys and gives 404 if no record updated" $
it "ignores json keys and gives 200 if no record updated" $
request methodPatch "/articles?id=eq.2001&columns=body" [("Prefer", "return=representation")]
[json| {"body": "Some real content", "smth": "here", "other": "stuff", "fake_id": 13} |] `shouldRespondWith` 404
[json| {"body": "Some real content", "smth": "here", "other": "stuff", "fake_id": 13} |] `shouldRespondWith` 200

context "tables with self reference foreign keys" $ do
it "embeds children after update" $
Expand Down

0 comments on commit 38dd893

Please sign in to comment.