Reading User-Agent Header in Servant

by||2 min read
Haskell Servant
Haskell Servant

Sometimes it is useful to read header values when processing a request. In this article we will see how to achieve this in a Servant application.

Why and where do we need this? In my case, I wanted to read the User-Agent string to decide if I redirect the request to a different location. Since my Currency Converter Chrome Extension only makes sense with a Chrome Browser, I wanted to redirect users with a Chrome Browser directly to the extension page. Otherwise I would provide a simple web version of the Currency Converter NEO.

As usual, let's see how it would be done in a very popular Web-Framework like Symfony:

public function getMyAction(Request $request)
  $userAgent = $request->headers->get('User-Agent');
  return new RedirectResponse('...');

As expected, we get the Request as an object from the action parameters. On this object we can access all headers we are interested in (i.e. User-Agent).

Servant on the other hand works a bit different. We can define the header access directly in our server path types:

type CurrencyConverterAPI = "currency-converter-neo" :> Header "User-Agent" Text :> Get '[HTML] (CurrencyConverterPage) 

As you can see, we match on the static string "currency-converter-neo" by a following Header definition. As well, we define a type that we expect, Text in this case. With this server route type we can access our header directly in out function:

currencyConverterPage :: (MonadIO m) => Maybe Text -> AppT m CurrencyConverterPage
currencyConverterPage mUserAgent = do
  -- TODO: Imlementation

Consequently our function expect a Maybe Text, since we can not be sure that the requested header is really set. Servant forces us a bit to check for both cases!

Thank you for reading this far! Let’s connect. You can @ me on Twitter (@debilofant) with comments, or feel free to follow. Please like/share this article so that it reaches others as well.

© Copyright 2022 - Ersocon - All rights reservedVer.