Skip to content

Commit 85bba5e

Browse files
committed
refactor: clarify content negotiation
1 parent 76fd411 commit 85bba5e

File tree

1 file changed

+16
-25
lines changed

1 file changed

+16
-25
lines changed

src/PostgREST/ApiRequest.hs

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ getAction PathInfo{pathIsProc, pathIsDefSpec} method =
207207

208208
getMediaTypes :: AppConfig -> RequestHeaders -> Action -> PathInfo -> Either ApiRequestError (MediaType, MediaType)
209209
getMediaTypes conf hdrs action path = do
210-
acceptMediaType <- findAcceptMediaType conf action path accepts
210+
acceptMediaType <- negotiateContent conf action path accepts
211211
pure (acceptMediaType, contentMediaType)
212212
where
213213
accepts = maybe [MTAny] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
@@ -299,19 +299,6 @@ getPayload reqBody contentMediaType QueryParams{qsColumns} action PathInfo{pathI
299299
ActionInvoke InvPost -> qsColumns
300300
_ -> Nothing
301301

302-
{-|
303-
Find the best match from a list of media types accepted by the
304-
client in order of decreasing preference and a list of types
305-
producible by the server. If there is no match but the client
306-
accepts */* then return the top server pick.
307-
-}
308-
mutuallyAgreeable :: [MediaType] -> [MediaType] -> Maybe MediaType
309-
mutuallyAgreeable sProduces cAccepts =
310-
let exact = listToMaybe $ L.intersect cAccepts sProduces in
311-
if isNothing exact && MTAny `elem` cAccepts
312-
then listToMaybe sProduces
313-
else exact
314-
315302
type CsvData = V.Vector (M.Map Text LBS.ByteString)
316303

317304
{-|
@@ -361,20 +348,24 @@ payloadAttributes raw json =
361348
where
362349
emptyPJArray = ProcessedJSON (JSON.encode emptyArray) S.empty
363350

364-
findAcceptMediaType :: AppConfig -> Action -> PathInfo -> [MediaType] -> Either ApiRequestError MediaType
365-
findAcceptMediaType conf action path accepts =
366-
case mutuallyAgreeable (requestMediaTypes conf action path) accepts of
367-
Just ct ->
368-
Right ct
369-
Nothing ->
370-
Left . MediaTypeError $ map MediaType.toMime accepts
371351

372-
requestMediaTypes :: AppConfig -> Action -> PathInfo -> [MediaType]
373-
requestMediaTypes conf action path =
352+
-- | Do content negotiation. i.e. choose a media type based on the intersection of accepted/produced media types.
353+
negotiateContent :: AppConfig -> Action -> PathInfo -> [MediaType] -> Either ApiRequestError MediaType
354+
negotiateContent conf action path accepts =
355+
case firstAcceptedPick of
356+
Just MTAny -> Right MTApplicationJSON -- by default(for */*) we respond with json
357+
Just mt -> Right mt
358+
Nothing -> Left . MediaTypeError $ map MediaType.toMime accepts
359+
where
360+
-- if there are multiple accepted media types, pick the first
361+
firstAcceptedPick = listToMaybe $ L.intersect accepts $ producedMediaTypes conf action path
362+
363+
producedMediaTypes :: AppConfig -> Action -> PathInfo -> [MediaType]
364+
producedMediaTypes conf action path =
374365
case action of
375366
ActionRead _ -> defaultMediaTypes ++ rawMediaTypes
376367
ActionInvoke _ -> invokeMediaTypes
377-
ActionInspect _ -> [MTOpenAPI, MTApplicationJSON]
368+
ActionInspect _ -> [MTOpenAPI, MTApplicationJSON, MTAny]
378369
ActionInfo -> defaultMediaTypes
379370
ActionMutate _ -> defaultMediaTypes
380371
where
@@ -384,5 +375,5 @@ requestMediaTypes conf action path =
384375
++ [MTOpenAPI | pathIsRootSpec path]
385376
defaultMediaTypes =
386377
[MTApplicationJSON, MTSingularJSON, MTGeoJSON, MTTextCSV] ++
387-
[MTPlan $ MTPlanAttrs Nothing PlanJSON mempty | configDbPlanEnabled conf]
378+
[MTPlan $ MTPlanAttrs Nothing PlanJSON mempty | configDbPlanEnabled conf] ++ [MTAny]
388379
rawMediaTypes = configRawMediaTypes conf `union` [MTOctetStream, MTTextPlain, MTTextXML]

0 commit comments

Comments
 (0)