I need to introduce a internalization in my servant
app in a backward compatible manner. I want to have the language code as an optional path segment. If the very fist path segment is from a known list of language codes, that language is used, else it defaults to Nothing
(which the handler/server would interpret as some default language).
/some/path => myHandler Nothing
/en/some/path => myHanddler (Just "en")
/fr/some/path => myHandler (Just "fr")
To avoid having to write the following boilerplate…
- Each endpoint will have two endpoints: one with the language code segment, and one without
- Therefore, the server/handler will also need to have two variants — one with language code and one without
…I wanted to come up with a servant combinator that “peeks” at head $ pathInfo req
and it if looks like a language-code, it captures it, else it passes along Nothing
to the sub-server.
I came up with the following, but can’t get it to type-check because I’m not sure how to use addCapture
along with passToServer
data MaybeLanguageCode = MaybeLanguageCode
knownLanguageCodes :: [Text]
knownLanguageCodes = ["en", "fr", "es"] -- etc
instance (HasServer api context) => HasServer (MaybeLanguageCode :> api) context where
type ServerT (MaybeLanguageCode :> api) m = (Maybe Text) -> ServerT api m
route _ context subserver =
route (Proxy :: Proxy api) context (passToServer subserver extractLanguageCode)
where
extractLanguageCode :: Request -> Maybe Text
extractLanguageCode req =
case pathInfo req of
[] -> Nothing
(x:_) -> if x `DL.elem` knownLanguageCodes
then addCapture _todo -- nothing that I do here will type-check, it seems
else Nothing