Supposing I'm running a Servant webserver, with two endpoints, with a type looking like this:
type BookAPI =
"books" :> Get '[JSON] (Map Text Text)
:<|> "book" :> Capture "Name" Text :> ReqBody '[JSON] (Text) :> Post '[JSON] (Text)
λ:T.putStrLn $ layout (Proxy :: Proxy BookAPI)
/
├─ book/
│ └─ <capture>/
│ └─•
└─ books/
└─•
I might want to use something like Network.Wai.Middleware.Prometheus's instrumentHandlerValue to generate a Prometheus metric that fire's every time this API is called, with a handler value set to the path of the request.
However, if I do something like the following:
prometheusMiddlware = instrumentHandlerValue (T.intercalate "\\" . pathInfo)
This is bad, because different requests to the book/<Name>
endpoint, such as book/great-expectations
and book/vanity-fair
result in different labels, this is fine if the number of books is small, but if it's very large then the amount of data used by these metrics is very big, and either my service falls over, or my monitoring bill becomes very large.
I'd quite like a function, that took a Servant API, and a Wai Request, and if it matched, returned a list of segments in a form that was the same for each endpoint.
That is requests to /books
would return Just ["books"]
, requests to /book/little-dorrit
would return Just ["book", "Name"]
, and requests to /films
would return Nothing
.
I can kind of see how you might go about writing this by pattern matching on Router'
from Servant.Server.Internal.Router, but it's not clear to me that relying on an internal package in order to do this is a good idea.
Is there a better way?