diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -31,8 +31,8 @@
 index :: ResponderM a
 index = send $ html "Hello World!"
 
-echo :: ResponderM a
-echo = do
+echoName :: ResponderM a
+echoName = do
   name <- param "name"
   send $ html $ "Hello, " <> name
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,19 @@
 # Change Log
 
+## 2.1.2.0 [2023-04-10]
+
+Bump version bounds for transformers so Twain can be built with GHC 9.6.1
+
+## 2.1.1.0 [2022-08-14]
+
+Add getters for query, path, and cookie params.
+
+## 2.1.0.0 [2022-04-22]
+
+- Remove ghc flag and add default-language.
+- Add tests
+- Add CSS response
+
 ## 2.0.0.0 [2022-01-09]
 
 Simplify API to decompose routes into WAI middleware.
diff --git a/src/Web/Twain.hs b/src/Web/Twain.hs
--- a/src/Web/Twain.hs
+++ b/src/Web/Twain.hs
@@ -48,6 +48,18 @@
     paramEither,
     paramMaybe,
     params,
+    queryParam,
+    queryParamMaybe,
+    queryParamEither,
+    queryParams,
+    pathParam,
+    pathParamMaybe,
+    pathParamEither,
+    pathParams,
+    cookieParam,
+    cookieParamMaybe,
+    cookieParamEither,
+    cookieParams,
     file,
     fileMaybe,
     files,
@@ -222,6 +234,99 @@
 -- | Get all parameters from query, path, cookie, and body (in that order).
 params :: ResponderM [Param]
 params = concatParams <$> parseBodyForm
+
+-- | Get a query parameter.
+--
+-- If no parameter is found, or parameter fails to parse, `next` is called
+-- which passes control to subsequent routes and middleware.
+queryParam :: ParsableParam a => Text -> ResponderM a
+queryParam name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> queryParams
+  maybe next (either (const next) pure . parseParam) pM
+
+-- | Get a query parameter or error if missing or parse failure.
+queryParamEither :: ParsableParam a => Text -> ResponderM (Either HttpError a)
+queryParamEither name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> queryParams
+  return $ case pM of
+    Nothing ->
+      Left $ HttpError status400 ("missing parameter: " <> T.unpack name)
+    Just p -> parseParam p
+
+-- | Get an optional query parameter.
+--
+-- Returns `Nothing` for missing parameter.
+-- Throws `HttpError` on parse failure.
+queryParamMaybe :: ParsableParam a => Text -> ResponderM (Maybe a)
+queryParamMaybe name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> queryParams
+  return $ maybe Nothing (rightToMaybe . parseParam) pM
+
+-- | Get all query parameters.
+queryParams :: ResponderM [Param]
+queryParams = preqQueryParams <$> parseBodyForm
+
+-- | Get a path parameter.
+--
+-- If no parameter is found, or parameter fails to parse, `next` is called
+-- which passes control to subsequent routes and middleware.
+pathParam :: ParsableParam a => Text -> ResponderM a
+pathParam name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> pathParams
+  maybe next (either (const next) pure . parseParam) pM
+
+-- | Get a path parameter or error if missing or parse failure.
+pathParamEither :: ParsableParam a => Text -> ResponderM (Either HttpError a)
+pathParamEither name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> pathParams
+  return $ case pM of
+    Nothing ->
+      Left $ HttpError status400 ("missing parameter: " <> T.unpack name)
+    Just p -> parseParam p
+
+-- | Get an optional path parameter.
+--
+-- Returns `Nothing` for missing parameter.
+-- Throws `HttpError` on parse failure.
+pathParamMaybe :: ParsableParam a => Text -> ResponderM (Maybe a)
+pathParamMaybe name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> pathParams
+  return $ maybe Nothing (rightToMaybe . parseParam) pM
+
+-- | Get all path parameters.
+pathParams :: ResponderM [Param]
+pathParams = preqPathParams <$> parseBodyForm
+
+-- | Get a cookie parameter.
+--
+-- If no parameter is found, or parameter fails to parse, `next` is called
+-- which passes control to subsequent routes and middleware.
+cookieParam :: ParsableParam a => Text -> ResponderM a
+cookieParam name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> cookieParams
+  maybe next (either (const next) pure . parseParam) pM
+
+-- | Get a cookie parameter or error if missing or parse failure.
+cookieParamEither :: ParsableParam a => Text -> ResponderM (Either HttpError a)
+cookieParamEither name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> cookieParams
+  return $ case pM of
+    Nothing ->
+      Left $ HttpError status400 ("missing parameter: " <> T.unpack name)
+    Just p -> parseParam p
+
+-- | Get an optional cookie parameter.
+--
+-- Returns `Nothing` for missing parameter.
+-- Throws `HttpError` on parse failure.
+cookieParamMaybe :: ParsableParam a => Text -> ResponderM (Maybe a)
+cookieParamMaybe name = do
+  pM <- fmap snd . L.find ((==) name . fst) <$> cookieParams
+  return $ maybe Nothing (rightToMaybe . parseParam) pM
+
+-- | Get all cookie parameters.
+cookieParams :: ResponderM [Param]
+cookieParams = preqCookieParams <$> parseBodyForm
 
 -- | Get uploaded `FileInfo`.
 --
diff --git a/src/Web/Twain/Internal.hs b/src/Web/Twain/Internal.hs
--- a/src/Web/Twain/Internal.hs
+++ b/src/Web/Twain/Internal.hs
@@ -64,7 +64,7 @@
       ParsedRequest
         { preqPathParams = [],
           preqQueryParams = decodeQueryParam <$> queryString req,
-          preqCookieParams = cookieParams req,
+          preqCookieParams = parseCookieParams req,
           preqBody = Nothing
         }
 
@@ -120,8 +120,8 @@
   let msg' = unpack $ decodeUtf8 msg
   throwIO $ HttpError status500 msg'
 
-cookieParams :: Request -> [Param]
-cookieParams req =
+parseCookieParams :: Request -> [Param]
+parseCookieParams req =
   let headers = snd <$> L.filter ((==) hCookie . fst) (requestHeaders req)
    in join $ parseCookiesText <$> headers
 
diff --git a/twain.cabal b/twain.cabal
--- a/twain.cabal
+++ b/twain.cabal
@@ -5,7 +5,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           twain
-version:        2.1.0.0
+version:        2.1.2.0
 synopsis:       Tiny web application framework for WAI.
 description:    Twain is tiny web application framework for WAI. It provides routing, parameter parsing, and an either-like monad for composing responses.
 category:       Web
@@ -47,7 +47,7 @@
     , http2 >=1.0.0 && <3.3.0
     , text >=1.2.3 && <3
     , time >=1.8 && <2
-    , transformers >=0.5.6 && <0.6
+    , transformers >=0.5.6 && <0.7
     , vault ==0.3.*
     , wai ==3.2.*
     , wai-extra >=3.0 && <3.2
