@@ -139,7 +139,7 @@ toApplication ra request respond = ra request routingRespond
139139-- Therefore, while routing, we delay most checks so that they
140140-- will ultimately occur in the right order.
141141--
142−-- A 'Delayed' contains three delayed blocks of tests, and
142+-- A 'Delayed' contains four delayed blocks of tests, and
143143-- the actual handler:
144144--
145145-- 1. Delayed captures. These can actually cause 404, and
@@ -148,27 +148,36 @@ toApplication ra request respond = ra request routingRespond
148148-- check order from the error reporting, see above). Delayed
149149-- captures can provide inputs to the actual handler.
150150--
151−-- 2. Method check(s). This can cause a 405. On success,
151+-- 2. Query parameter checks. They require parsing and can cause 400 if the
152+-- parsing fails. Query parameter checks provide inputs to the handler
153+--
154+-- 3. Method check(s). This can cause a 405. On success,
152155-- it does not provide an input for the handler. Method checks
153156-- are comparatively cheap.
154157--
155−-- 3. Body and accept header checks. The request body check can
158+-- 4. Body and accept header checks. The request body check can
156159-- cause both 400 and 415. This provides an input to the handler.
157160-- The accept header check can be performed as the final
158161-- computation in this block. It can cause a 406.
159162--
160163data Delayed env c where
161164 Delayed :: { capturesD :: env -> DelayedIO captures
165+ , paramsD :: DelayedIO params
162166 , methodD :: DelayedIO ()
163167 , authD :: DelayedIO auth
164168 , bodyD :: DelayedIO body
165− , serverD :: captures -> auth -> body -> Request -> RouteResult c
169+ , serverD :: captures
170+ -> params
171+ -> auth
172+ -> body
173+ -> Request
174+ -> RouteResult c
166175 } -> Delayed env c
167176
168177instance Functor (Delayed env) where
169178 fmap f Delayed{..} =
170179 Delayed
171− { serverD = \ c a b req -> f <$> serverD c a b req
180+ { serverD = \ c p a b req -> f <$> serverD c p a b req
172181 , ..
173182 } -- Note [Existential Record Update]
174183
@@ -200,7 +209,7 @@ runDelayedIO m req = transResourceT runRouteResultT $ runReaderT (runDelayedIO'
200209-- | A 'Delayed' without any stored checks.
201210emptyDelayed :: RouteResult a -> Delayed env a
202211emptyDelayed result =
203− Delayed (const r) r r r (\ _ _ _ _ -> result)
212+ Delayed (const r) r r r r (\ _ _ _ _ _ -> result)
204213 where
205214 r = return ()
206215
@@ -225,10 +234,21 @@ addCapture :: Delayed env (a -> b)
225234addCapture Delayed{..} new =
226235 Delayed
227236 { capturesD = \ (txt, env) -> (,) <$> capturesD env <*> new txt
228− , serverD = \ (x, v) a b req -> ($ v) <$> serverD x a b req
237+ , serverD = \ (x, v) p a b req -> ($ v) <$> serverD x p a b req
229238 , ..
230239 } -- Note [Existential Record Update]
231240
241+-- | Add a parameter check to the end of the params block
242+addParameterCheck :: Delayed env (a -> b)
243+ -> DelayedIO a
244+ -> Delayed env b
245+addParameterCheck Delayed {..} new =
246+ Delayed
247+ { paramsD = (,) <$> paramsD <*> new
248+ , serverD = \c (p, pNew) a b req -> ($ pNew) <$> serverD c p a b req
249+ , ..
250+ }
251+
232252-- | Add a method check to the end of the method block.
233253addMethodCheck :: Delayed env a
234254 -> DelayedIO ()
@@ -246,7 +266,7 @@ addAuthCheck :: Delayed env (a -> b)
246266addAuthCheck Delayed{..} new =
247267 Delayed
248268 { authD = (,) <$> authD <*> new
249− , serverD = \ c (y, v) b req -> ($ v) <$> serverD c y b req
269+ , serverD = \ c p (y, v) b req -> ($ v) <$> serverD c p y b req
250270 , ..
251271 } -- Note [Existential Record Update]
252272
@@ -257,7 +277,7 @@ addBodyCheck :: Delayed env (a -> b)
257277addBodyCheck Delayed{..} new =
258278 Delayed
259279 { bodyD = (,) <$> bodyD <*> new
260− , serverD = \ c a (z, v) req -> ($ v) <$> serverD c a z req
280+ , serverD = \ c p a (z, v) req -> ($ v) <$> serverD c p a z req
261281 , ..
262282 } -- Note [Existential Record Update]
263283
@@ -287,7 +307,7 @@ addAcceptCheck Delayed{..} new =
287307passToServer :: Delayed env (a -> b) -> (Request -> a) -> Delayed env b
288308passToServer Delayed{..} x =
289309 Delayed
290− { serverD = \ c a b req -> ($ x req) <$> serverD c a b req
310+ { serverD = \ c p a b req -> ($ x req) <$> serverD c p a b req
291311 , ..
292312 } -- Note [Existential Record Update]
293313
@@ -301,16 +321,14 @@ runDelayed :: Delayed env a
301321 -> env
302322 -> Request
303323 -> ResourceT IO (RouteResult a)
304−runDelayed Delayed{..} env req =
305− runDelayedIO
306− (do c <- capturesD env
307− methodD
308− a <- authD
309− b <- bodyD
310− r <- ask
311− liftRouteResult (serverD c a b r)
312− )
313− req
324+runDelayed Delayed{..} env = runDelayedIO $ do
325+ c <- capturesD env
326+ methodD
327+ a <- authD
328+ b <- bodyD
329+ r <- ask
330+ p <- paramsD -- Has to be after body to respect the relative error order
331+ liftRouteResult (serverD c p a b r)
314332
315333-- | Runs a delayed server and the resulting action.
316334-- Takes a continuation that lets us send a response.