Skip to content

Commit 3bef99b

Browse files
committed
fix: content-type not set with custom domain and accept */*
BREAKING CHANGE This is a WIP commit and needs discussion. Add description here later Signed-off-by: Taimoor Zaeem <taimoorzaeem@gmail.com>
1 parent c561a37 commit 3bef99b

File tree

6 files changed

+62
-15
lines changed

6 files changed

+62
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. From versio
44

55
## Unreleased
66

7+
## Fixed
8+
9+
- WIP, add changelog later.
10+
711
## [14.1] - 2025-11-05
812

913
## Fixed

src/PostgREST/ApiRequest.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ userApiRequest conf prefs req reqBody = do
9898
, iMethod = method
9999
, iSchema = schema
100100
, iNegotiatedByProfile = negotiatedByProfile
101-
, iAcceptMediaType = maybe [MTAny] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
101+
, iAcceptMediaType = maybe [MTApplicationJSON] (map MediaType.decodeMediaType . parseHttpAccept) $ lookupHeader "accept"
102102
, iContentMediaType = contentMediaType
103103
}
104104
where

src/PostgREST/Plan.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,9 +1140,10 @@ negotiateContent conf ApiRequest{iAction=act, iPreferences=Preferences{preferRep
11401140
x -> lookupHandler x
11411141
mtPlanToNothing x = if configDbPlanEnabled conf then x else Nothing -- don't find anything if the plan media type is not allowed
11421142
lookupHandler mt =
1143-
when' defaultSelect (HM.lookup (RelId identifier, MTAny) produces) <|> -- lookup for identifier and `*/*`
1144-
when' defaultSelect (HM.lookup (RelId identifier, mt) produces) <|> -- lookup for identifier and a particular media type
1145-
HM.lookup (RelAnyElement, mt) produces -- lookup for anyelement and a particular media type
1143+
when' defaultSelect (HM.lookup (RelId identifier, mt) produces) <|> -- lookup for identifier and a particular media type
1144+
HM.lookup (RelAnyElement , mt) produces <|> -- lookup for anyelement and a particular media type
1145+
when' defaultSelect (HM.lookup (RelId identifier, MTAny) produces) -- lookup for identifier and */* media type
1146+
11461147
when' :: Bool -> Maybe a -> Maybe a
11471148
when' True (Just a) = Just a
11481149
when' _ _ = Nothing

src/PostgREST/SchemaCache.hs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,17 +1078,45 @@ mediaHandlers =
10781078
proc.pronamespace = ANY($$1::regnamespace[]) and NOT proretset
10791079
and prokind = 'f'|]
10801080

1081+
-- We take the union of two maps:
1082+
-- First map builds the mapping of domain types -> resolved media type
1083+
-- Second map creates the same mapping, but with "*/*" key
1084+
-- Example:
1085+
-- +------------------------------------------------+
1086+
-- | domain type | resolved media type |
1087+
-- +------------------------------------------------+
1088+
-- | text/plain | text/plain |
1089+
-- +------------------------------------------------+
1090+
-- | */* | text/plain |
1091+
-- +------------------------------------------------+
1092+
-- This allows us to resolve to "text/plain" on both
1093+
-- "Accept: text/plain" and
1094+
-- "Accept: */*"
1095+
--
1096+
-- TODO: This basically doubles the size of the map, so we should do some
1097+
-- production scale memory tests to make sure with aren't hitting OOM errors
10811098
decodeMediaHandlers :: HD.Result MediaHandlerMap
1082-
decodeMediaHandlers =
1083-
HM.fromList . fmap (\(x, y, z, w) ->
1084-
let rel = if isAnyElement y then RelAnyElement else RelId y
1085-
in ((rel, z), (CustomFunc x rel, w)) ) <$> HD.rowList caggRow
1086-
where
1087-
caggRow = (,,,)
1088-
<$> (QualifiedIdentifier <$> column HD.text <*> column HD.text)
1089-
<*> (QualifiedIdentifier <$> column HD.text <*> column HD.text)
1090-
<*> (MediaType.decodeMediaType . encodeUtf8 <$> column HD.text)
1091-
<*> (MediaType.decodeMediaType . encodeUtf8 <$> column HD.text)
1099+
decodeMediaHandlers = mapFromList <$> HD.rowList caggRow
1100+
where
1101+
mapFromList aggRowList =
1102+
HM.union
1103+
(HM.fromList . fmap (aggRowToList False) $ aggRowList) -- type -> type map
1104+
(HM.fromList . fmap (aggRowToList True) $ aggRowList) -- */* -> type map
1105+
1106+
caggRow = (,,,)
1107+
<$> (QualifiedIdentifier <$> column HD.text <*> column HD.text)
1108+
<*> (QualifiedIdentifier <$> column HD.text <*> column HD.text)
1109+
<*> (MediaType.decodeMediaType . encodeUtf8 <$> column HD.text)
1110+
<*> (MediaType.decodeMediaType . encodeUtf8 <$> column HD.text)
1111+
1112+
aggRowToList withMTAny (x,y,z,w) = ((rel, mt), (CustomFunc x rel, w))
1113+
where
1114+
-- we don't add the */* mapping when rel is "anyelement" because we
1115+
-- already have (RelAnyElement, MTAny) in the initial media handler
1116+
-- map which maps to "application/json"
1117+
mt = if withMTAny && (rel /= RelAnyElement) then MediaType.MTAny else z
1118+
rel = if isAnyElement y then RelAnyElement else RelId y
1119+
10921120

10931121
timezones :: Bool -> SQL.Statement () TimezoneNames
10941122
timezones = SQL.Statement sql HE.noParams decodeTimezones

test/spec/Feature/Query/CustomMediaSpec.hs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ spec = describe "custom media types" $ do
116116
, matchHeaders = ["Content-Type" <:> "text/xml; charset=utf-8"]
117117
}
118118

119+
it "should get the return type of function when accept is */*" $ do
120+
request methodGet "/rpc/javascript"
121+
[("Accept", "*/*")]
122+
""
123+
`shouldRespondWith`
124+
"This is Javascript."
125+
{ matchStatus = 200
126+
, matchHeaders = ["Content-Type" <:> "text/javascript"]
127+
}
128+
119129
it "should fail with function returning text and Accept: text/xml" $ do
120130
request methodGet "/rpc/welcome" (acceptHdrs "text/xml") ""
121131
`shouldRespondWith`

test/spec/fixtures/schema.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ SET search_path = test, pg_catalog;
107107
SET default_tablespace = '';
108108

109109
SET default_with_oids = false;
110-
110+
create domain "text/javascript" as text;
111111
create domain "text/plain" as text;
112112
create domain "text/html" as text;
113113
create domain "text/xml" as pg_catalog.xml;
@@ -1884,6 +1884,10 @@ create or replace function welcome() returns "text/plain" as $$
18841884
select 'Welcome to PostgREST'::"text/plain";
18851885
$$ language sql;
18861886

1887+
create or replace function javascript() returns "text/javascript" as $$
1888+
select 'This is Javascript.'::"text/javascript";
1889+
$$ language sql;
1890+
18871891
create or replace function welcome_twice() returns setof "text/plain" as $$
18881892
select 'Welcome to PostgREST'
18891893
union all

0 commit comments

Comments
 (0)