Routing.Duplex
- Package
- purescript-routing-duplex
- Repository
- natefaubion/purescript-routing-duplex
#RouteDuplex Source
data RouteDuplex i o
The core abstraction of this library. The values of this type can be used both for parsing
values of type o
from String
as well as printing values of type i
into String
.
For most purposes, you'll likely want RouterDuplex'
which uses the same
type for both parameters.
Constructors
RouteDuplex (i -> RoutePrinter) (RouteParser o)
Instances
Functor (RouteDuplex i)
Apply (RouteDuplex i)
Applicative (RouteDuplex i)
Profunctor RouteDuplex
(IsSymbol sym, Cons sym (RouteDuplex String String -> RouteDuplex a b) rx1 r1, Cons sym a rx2 r2, Cons sym b r3 rx3, Lacks sym r3, RouteDuplexBuildParams rest r1 r2 rx3 r4) => RouteDuplexBuildParams (Cons sym (RouteDuplex String String -> RouteDuplex a b) rest) r1 r2 r3 r4
#RouteDuplex' Source
type RouteDuplex' a = RouteDuplex a a
A type restricted variant of RouteDuplex
where input and output are
the same type. This type will typically be your custom Route
data type
representing valid routes within your application.
#parse Source
parse :: forall o i. RouteDuplex i o -> String -> Either RouteError o
Uses a given codec to parse a value of type o
out of String representing
the path, query and fragment (hash) of a URI (see
URI - generic syntax)
or produce a RouteError
if parsing fails.
#print Source
print :: forall o i. RouteDuplex i o -> i -> String
Renders a value of type i
into a String representation of URI path,
query and fragment (hash).
#prefix Source
prefix :: forall b a. String -> RouteDuplex a b -> RouteDuplex a b
Strips (when parsing) or adds (when printing) a given string segment of the
path. Note: this combinator only deals with a single segment.
If you pass it a string containing '/' it will percent encode it and treat it as single segment.
E.g. prefix "/api/v1"
will attempt to match single segment "%2Fapi%2Fv1"
which is probably not what you want.
See path
if you want to deal with prefixes consisting of multiple segments.
parse (prefix "api" segment) "api/a" == Right "a"
parse (prefix "/api/v1" segment)) "/api/v1/a" == Left (Expected "/api/v1" "")
-- contrast with `path`
parse (path "/api/v1" segment)) "/api/v1/a" == Right "a"
#suffix Source
suffix :: forall b a. RouteDuplex a b -> String -> RouteDuplex a b
Similar to prefix
. Strips (when parsing) or adds (when printing) a given
string segment from the end of the path. The same precautions for prefix
apply here.
#path Source
path :: forall b a. String -> RouteDuplex a b -> RouteDuplex a b
Strips (when parsing) or adds (when printing) a given String prefix,
potentially consisting of multiple path segments. Constrast this with prefix
,
which only deals with single segment.
parse (path "/api/v1" segment) "/api/v1/a" == Right "a"
parse (path "/api/v1" segment) "/api/v2/a" == Left (Expected "v1" "v2")
#root Source
root :: forall b a. RouteDuplex a b -> RouteDuplex a b
Modifies a given codec to require a prefix of '/'. You can think of it as stripping and adding the '/' at the beginning of path, failing if it's not there.
parse (root segment) "/abc" == Right "abc"
parse (root segment) "abc" == Left (Expected "" "abc")
print (root segment) "abc" == "/abc"
#end Source
end :: forall b a. RouteDuplex a b -> RouteDuplex a b
end codec
will only suceed if codec
succeeds and there are no
additional path segments remaining to be processed.
parse (end segment) "abc" == Right "abc"
parse (end segment) "abc/def" == Left (ExpectedEndOfPath "def")
#segment Source
segment :: RouteDuplex' String
Consumes or prints a single path segment. Note: URI encoding and decoding is done automatically.
parse segment "abc" == Right "abc"
parse segment "abc%20def" == Right "abc def" -- automatic decoding of uri components
parse segment "abc/def" == Right "abc"
parse segment "/abc" == Right "" -- the empty string before the first '/'
parse (root segment) "/abc" == Right "abc"
print segment "hello there" == "hello%20there"
print segment "" == "/"
#param Source
param :: String -> RouteDuplex' String
param name
consumes or prints a query parameter with the given name
.
Parsing will fail if the parameter is not there.
parse (param "search") "?search=keyword" == Right "keyword"
parse (param "search") "/" == Left (MissingParam "search")
parse (optional (param "search")) "/" == Right Nothing
#flag Source
flag :: RouteDuplex' String -> RouteDuplex' Boolean
Consumes or prints a query flag (i.e. parameter without value).
Note: that this combinator ignores the value of the parameter. It only cares about its presence/absence.
Presence is interpreted as true
, absence as false
.
parse (flag (param "x")) "?x" == Right true
parse (flag (param "x")) "?x=true", == Right true
parse (flag (param "x")) "?x=false", == Right true -- value is ignored, what matters is presence of the parameter x
parse (flag (param "x")) "?y", == Right false
#many1 Source
many1 :: forall b a f. Foldable f => Alt f => Applicative f => RouteDuplex a b -> RouteDuplex (f a) (f b)
Repeatedly applies a given codec to parse one or more values from path segments. Parsing will fail if no segment can be parsed.
parse (many1 (int segment)) "1/2/3/x" == Right [1,2,3]
parse (many1 (int segment)) "x", == Left (Expected "Int" "x") :: Either RouteError (Array Int)
#many Source
many :: forall b a f. Foldable f => Alternative f => RouteDuplex a b -> RouteDuplex (f a) (f b)
Similar to many1
, except also succeeds when no values can be parsed.
parse (many (int segment)) "1/2/3/x" == Right [1,2,3]
parse (many (int segment)) "x", == Right []
#rest Source
rest :: RouteDuplex' (Array String)
Consumes or prints all the remaining segments.
parse rest "" == Right []
parse (path "a/b" rest) "a/b/c/d" == Right ["c", "d"]
print rest ["a", "b"] == "a/b"
#default Source
default :: forall b a. b -> RouteDuplex a b -> RouteDuplex a b
Sets a default value which will be returned when parsing fails. Does not influence printing in any way.
parse (default 0 $ int segment) "1" == Right 1
parse (default 0 $ int segment) "x" == Right 0
#optional Source
optional :: forall b a. RouteDuplex a b -> RouteDuplex (Maybe a) (Maybe b)
Augments the behavior of a given codec by making it return Nothing
if parsing
fails, or Just value
if it succeeds.
parse (optional segment) "a" == Right (Just "a")
parse (optional segment) "" == Right Nothing
print (optional segment) (Just "a") == "a"
print (optional segment) Nothing == ""
#as Source
as :: forall b a s. (a -> s) -> (String -> Either String b) -> RouteDuplex s String -> RouteDuplex a b
Builds a codec for a custom type out of printer and parser functions.
data Sort = Asc | Desc
sortToString :: Sort -> String
sortToString = case _ of
Asc -> "asc"
Desc -> "desc"
sortFromString :: String -> Either String Sort
sortFromString = case _ of
"asc" -> Right Asc
"desc" -> Right Desc
val -> Left $ "Not a sort: " <> val
sort :: RouteDuplex' String -> RouteDuplex' Sort
sort = as sortToString sortFromString
#int Source
int :: RouteDuplex' String -> RouteDuplex' Int
Refines a codec of Strings to Ints.
parse (int segment) "1" == Right 1
parse (int segment) "x" == Left (Expected "Int" "x")
print (int segment) 1 == "1"
#boolean Source
boolean :: RouteDuplex' String -> RouteDuplex' Boolean
Refines a codec of Strings to Booleans, where true
and false
are the
strings "true"
and "false"
, and other strings are rejected.
parse (boolean segment) "true" == Right true
parse (boolean segment) "x" == Left (Expected "Boolean" "x")
print (boolean segment) true == "true"
#string Source
string :: RouteDuplex' String -> RouteDuplex' String
This does nothing (internally it's defined as identity).
It can be used to restrict a type parameter of a polymorphic RouteDuplex' a
to String
.
#record Source
record :: forall r. RouteDuplex r (Record ())
Combined with prop
or :=
, builds a Record where the order of
parsing and printing matters.
date =
record
# prop (SProxy :: _ "year") (int segment)
# prop (SProxy :: _ "month") (int segment)
# prop (SProxy :: _ "day") (int segment)
parse (path "blog" date) "blog/2019/1/2" ==
Right { year: 2019, month: 1, day: 2 }
#prop Source
prop :: forall rx r3 r2 r1 b a sym. IsSymbol sym => Cons sym a rx r1 => Cons sym b r2 r3 => Lacks sym r2 => SProxy sym -> RouteDuplex a b -> RouteDuplex (Record r1) (Record r2) -> RouteDuplex (Record r1) (Record r3)
See record
.
#RouteDuplexParams Source
class RouteDuplexParams (r1 :: Row Type) (r2 :: Row Type) | r1 -> r2 where
Members
params :: Record r1 -> RouteDuplex' (Record r2)
Instances
(RowToList r1 rl, RouteDuplexBuildParams rl r1 r2 () r2) => RouteDuplexParams r1 r2
#RouteDuplexBuildParams Source
class RouteDuplexBuildParams (rl :: RowList) (r1 :: Row Type) (r2 :: Row Type) (r3 :: Row Type) (r4 :: Row Type) | rl -> r1 r2 r3 r4 where
Members
buildParams :: RLProxy rl -> Record r1 -> RouteDuplex (Record r2) (Record r3) -> RouteDuplex (Record r2) (Record r4)
Instances
(IsSymbol sym, Cons sym (RouteDuplex String String -> RouteDuplex a b) rx1 r1, Cons sym a rx2 r2, Cons sym b r3 rx3, Lacks sym r3, RouteDuplexBuildParams rest r1 r2 rx3 r4) => RouteDuplexBuildParams (Cons sym (RouteDuplex String String -> RouteDuplex a b) rest) r1 r2 r3 r4
RouteDuplexBuildParams Nil r1 r2 r3 r3
Builds a
RouteDuplex
from a record of query parameter parsers/printers, where each property corresponds to a query parameter with the same name.