This library works with pre 0.12.0 releases of the compiler. It probably won't be upgraded.
If you are interested in routing solutions please check my another (I think superior) library paluh/purescript-boomboom which I plan to maintain, develop and adapt to 0.12.0
.
Let me introduce to you Bob The Router (known also as "Pendulum Bob") - simple (but usable) example of partial bidirectional routes generator based on purescript-boomerang and purescript-generics.
bower install purescript-routing-bob
Just to give you a hint what this library does, let's copy some tests' fragments (sorry for long data types and constructor names):
-
simple, union type:
import Data.Generic (class Generic) import Routing.Bob (bob, toUrl, fromUrl) import Type.Proxy (Proxy(..)) data UnionOfPrimitivePositionalValues = FirstConstructor Int Boolean Int | SecondConstructor Boolean derive instance genericUnionOfPrimitivePositionalValues :: Generic UnionOfPrimitivePositionalValues -- and related tests' lines equal (Just "first-constructor/8/on/9") (genericToUrl (FirstConstructor 8 true 9)) equal (Just "second-constructor/off") (genericToUrl (SecondConstructor false)) equal (Just (FirstConstructor 8 true 9)) (genericFromUrl "first-constructor/8/on/9") equal (Just (SecondConstructor false)) (genericFromUrl "second-constructor/off") -- below more realistic and faster implementation with pregenerated router -- notice that toUrl used on router generates value without Maybe wrapping let fObj = FirstConstructor 8 true 9 sObj = SecondConstructor false -- generting route for given type type: maybeRouter = router (Proxy :: Proxy UnionOfPrimitivePositionalValues) -- later we can use `router` (unrapped from Maybe) for url generation and url parsing: equal ("first-constructor/8/on/9") (toUrl router fObj) equal ("second-constructor/off") (toUrl router sObj) equal (Just fObj) (fromUrl router "first-constructor/8/on/9") equal (Just sObj) (fromUrl router "second-constructor/off")
-
netsted data type:
data PrimitivePositionalValues = PrimitivePositionalValues Int Boolean Int derive instance genericPrimitivePositionalValues :: Generic PrimitivePositionalValues data NestedStructures = FirstOuterConstructor UnionOfPrimitivePositionalValues | SecondOuterConstructor PrimitivePositionalValues derive instance genericNestedStructures :: Generic NestedStructures let fObj = FirstOuterConstructor (FirstConstructor 100 true 888) maybeRouter = router (Proxy :: Proxy NestedStructures) equal ("first-outer-constructor/first-constructor/100/on/888") (toUrl router fObj) equal (Just fObj) (fromUrl router "first-outer-constructor/first-constructor/100/on/888")) let sObj = SecondOuterConstructor (PrimitivePositionalValues 8 false 100) -- in case of single constructor (`PrimitivePositionalValues` has one), -- constructor name is omited in encoded url equal ("second-outer-constructor/8/off/100") (toUrl router sObj) equal (Just sObj) (fromUrl router "second-outer-constructor/8/off/100"))
-
records are converted into query (there is still some error handling missing...):
data SumWithInternalRecords = FirstConstructorWithRecord Int { int1 :: Int , string1 :: String } | SecondConstructorWithRecord String { int2 :: Int , string2 :: String , boolean2 :: Boolean } let fObj = FirstConstructorWithRecord 8 { int1: 8, string1: "string1" } sObj = SecondConstructorWithRecord "test" { int2: 8, string2: "string1", boolean2: false } equal "first-constructor-with-record/8/?string1=string1&int1=8" (toUrl router fObj) equal "second-constructor-with-record/test/?string2=string1&int2=8&boolean2=off" (toUrl router sObj))
-
data types isomorphic to
Data.Maybe.Maybe
are treated as optional values in queries:data Optional a = Value a | Missing derive instance genericOptional :: Generic a => Generic (Optional a) newtype ParamsWithOptionals = ParamsWithOptionals { optParamString :: Optional String , optParamInt :: Optional Int , optParamBoolean :: Optional Boolean } derive instance genericParamsWithOptionals :: Generic ParamsWithOptionals ... let fObj = ParamsWithOptionals { optParamString: Value "test", optParamInt: Missing, optParamBoolean: Missing} sObj = ParamsWithOptionals { optParamString: Missing, optParamInt: Value 8, optParamBoolean: Missing} ... equal "?optParamString=test" (toUrl r fObj) equal (Just sObj) (fromUrl r "?optParamInt=8&optParamBoolean="))
Not all types and language constructs are covered by this library. Some are treated differently in records than in paths.
In general sum and product types are encoded as url path, but if you use records as a value in any field it will correspond to query parameters (there is no name collission detection implemented yet, so don't use the same names for records fields). You can have arbitrary nesting of data types which will be translated into nested paths of constructors follwed by related values (only values of records fields are encoded in urls).
Here you have internal representation of language constructs which are already covered by this library:
type DataConstructorF r = { sigConstructor :: String, sigValues :: List r}
data SigF r
= SigProdF String (NonEmpty List (DataConstructorF r))
| SigRecordF (NonEmpty List ({ recLabel :: String, recValue :: (SigRecValueF r) }))
| SigBooleanF
| SigIntF
| SigStringF
type JustConstructorName = String
type NothingConstrtuctorName = String
data SigRecValueF r
= SigRecRequiredValueF r
| SigRecOptionalValueF JustConstructorName NothingConstrtuctorName r
| SigRecArrayF r
If you have any ideas how to nicely extend this set please let me know...
You can check test/Main.purs
for more examples... real docs comming soooooon ;-)