I'm using Servant generic, and have a datatype for my routes:
data Routes route = Routes
{ getLiveness :: route :- GetLiveness,
getReadiness :: route :- GetReadiness,
getAuthVerifyEmailToken :: route :- GetAuthVerifyEmailToken,
postAuthEmail :: route :- PostAuthEmail,
...
}
deriving (Generic)
type BackendPrefix = "backend"
type AuthPrefix = "auth"
type GetLiveness = BackendPrefix :> "liveness" :> Get '[JSON] Text
type GetReadiness = BackendPrefix :> "readiness" :> Get '[JSON] Text
type GetAuthVerifyEmailToken = AuthPrefix :> "verify" :> "email" :> Capture "token" JWT :> RedirectResponse '[PlainText] NoContent
type PostAuthEmail = AuthPrefix :> "email" :> ReqBody '[JSON] AuthEmailRequest :> PostNoContent
The first two use the same prefix "backend"
, and all other's have an "auth"
prefix.
However, I now want to change the "auth
" prefix to "backend/auth". So I tried chaging:
type AuthPrefix = BackendPrefix :> "auth"
This results in an error
> • Expected a type, but
> ‘"auth"’ has kind
> ‘ghc-prim-0.6.1:GHC.Types.Symbol’
> • In the second argument of ‘(:>)’, namely ‘"auth"’
> In the type ‘BackendPrefix :> "auth"’
> In the type declaration for ‘AuthPrefix’
> |
> 34 | type AuthPrefix = BackendPrefix :> "auth"
> |
So I googled and found you can do this when not using generic you can do:
type APIv1 = "api" :> "v1" :> API
But I couldn't figure out how to do this with generics.
I guess that leaves two questions:
type AuthPrefix = BackendPrefix :> "auth"
to create a more complex prefix?:>
is infixr 4
, which means it's right-associative. Consider this type:
type GetFoo = "backend" :> "auth" :> "foo" :> Get '[JSON] Text
It's interpreted as if you parenthesized it like this:
type GetFoo = "backend" :> ("auth" :> ("foo" :> Get '[JSON] Text))
With the type synonym you tried, it would get parenthesized like this instead:
type GetFoo = ("backend" :> "auth") :> ("foo" :> Get '[JSON] Text)
And that's clearly not the same thing, and in fact not even valid.
To help understand, consider this ordinary Haskell code with no advanced types:
xs = 1:2:3:4:5:6:[]
ys = 1:2:4:8:16:32:[]
Now imagine you tried to write this:
zs = 1:2
xs = zs:3:4:5:6:[]
ys = zs:4:8:16:32:[]
The reason it doesn't work is the exact same reason you can't have your type synonym.
One final example:
x = 2 ^ 3 ^ 2 -- evaluates to 2 ^ (3 ^ 2) = 512
y = 2 ^ 3
x = y ^ 2 -- evaluates to (2 ^ 3) ^ 2 = 64