servant-routes-0.1.0.0: src/Servant/API/Routes/Route.hs
{- |
Module : Servant.API.Routes.Route
Copyright : (c) Frederick Pringle, 2025
License : BSD-3-Clause
Maintainer : freddyjepringle@gmail.com
Simple term-level representation of Servant API endpoints.
-}
module Servant.API.Routes.Route
( -- * API routes
-- | The 'Route' type is not sophisticated, and its internals are hidden.
-- Create 'Route's using 'Servant.API.Routes.Route.defRoute', and update its fields
-- using the provided [lenses](#g:optics).
Route
, defRoute
, renderRoute
-- * Optics #optics#
, routeMethod
, routePath
, routeParams
, routeRequestHeaders
, routeRequestBody
, routeResponse
, routeAuths
, add
)
where
import qualified Data.Set as Set
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import Lens.Micro
import Network.HTTP.Types.Method (Method)
import "this" Servant.API.Routes.Internal.Route
import "this" Servant.API.Routes.Param
import "this" Servant.API.Routes.Path
import "this" Servant.API.Routes.Request
import "this" Servant.API.Routes.Response
{- | Given a REST 'Method', create a default 'Route': root path (@"/"@) with no params,
headers, body, auths, or response.
-}
defRoute :: Method -> Route
defRoute method =
Route
{ _routeMethod = method
, _routePath = rootPath
, _routeParams = Set.empty
, _routeRequestHeaders = mempty
, _routeRequestBody = noRequest
, _routeResponse = noResponse
, _routeAuths = mempty
}
{- | Pretty-print a 'Route'. Note that the output is minimal and doesn't contain all the information
contained in a 'Route'. For full output, use the 'Data.Aeson.ToJSON' instance.
> ghci> renderRoute $ defRoute \"POST\"
> "POST /"
> ghci> :{
> ghci| renderRoute $
> ghci| defRoute \"POST\"
> ghci| & routePath %~ prependPathPart "api/v2"
> ghci| & routeParams .~ [singleParam @"p1" @T.Text, flagParam @"flag", arrayElemParam @"p2s" @(Maybe Int)]
> ghci| :}
> "POST /api/v2?p1=<Text>&flag&p2s=<[Maybe Int]>"
-}
renderRoute :: Route -> T.Text
renderRoute Route {..} =
mconcat
[ method
, " "
, path
, params
]
where
method = TE.decodeUtf8 _routeMethod
path = renderPath _routePath
params =
if null _routeParams
then ""
else "?" <> T.intercalate "&" (renderParam <$> Set.toList _routeParams)
add :: Ord a => ASetter s t (Set.Set a) (Set.Set a) -> a -> s -> t
add setter = over setter . Set.insert