miso
Copyright(C) 2016-2026 David M. Johnson
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Miso.Router

Description

Overview

Miso.Router provides a type-safe, bidirectional client-side router. A Haskell sum type represents your application's routes; the Router class encodes and decodes between that type and URL strings. The router is used together with uriSub or routerSub to react to browser navigation.

Approach 1 — Generic deriving (recommended)

{-# LANGUAGE DeriveGeneric, DeriveAnyClass, DerivingStrategies #-}
import GHC.Generics (Generic)
import Miso.Router

data Route
  = Index                                                    -- "/"
  | About                                                    -- "/about"
  | User (Capture "id" Int)                                 -- "/user/42"
  | Search (QueryParam "q" MisoString)         -- "/search?q=foo"
  deriving stock (Show, Eq, Generic)
  deriving anyclass Router

Decoding:

toRoute "/user/42"  -- Right (User (Capture 42))
toRoute "/search?q=hello" -- Right (Search (QueryParam (Just "hello")))

Encoding (type-safe links):

prettyRoute (User (Capture 42))       -- "/user/42"
button_ [ href_ (User (Capture 42)) ] [ text "Profile" ]

Approach 2 — Manual instance

data Route = Widget Int deriving (Show, Eq)

instance Router Route where
  routeParser = routes [ Widget <$> (path "widget" *> capture) ]
  fromRoute (Widget n) = [ toPath "widget", toCapture n ]

Generic naming rules

  • Constructor name becomes the lowercase path segment: About/about, UserProfile/user (first camel-case hump only).
  • The special name Index encodes the root path /.
  • The position of Capture and Path fields in the constructor determines their order in the URL path. The position of QueryParam and QueryFlag does not matter.

URL types

Capture sym a
dynamic path segment — Capture 42/42
Path sym
fixed path segment — Path "foo"/foo
QueryParam sym a
optional query key — QueryParam (Just 1)?sym=1
QueryFlag sym
boolean query flag — QueryFlag True?sym
Fragment sym
hash fragment — Fragment#sym

Integration with history subscription

import Miso.Subscription.History (routerSub)

subs :: [Sub Action]
subs = [ routerSub RouteChanged ]

See also

Synopsis

Classes

class Router route where Source #

Class used to facilitate routing for miso applications

Minimal complete definition

Nothing

Methods

fromRoute :: route -> [Token] Source #

default fromRoute :: (Generic route, GRouter (Rep route)) => route -> [Token] Source #

toURI :: route -> URI Source #

Convert a 'Router route => route' into a URI

route :: URI -> Either RoutingError route Source #

Map a URI back to a route

href_ :: route -> Attribute action Source #

Convenience for specifying a URL as a hyperlink reference in View

prettyRoute :: route -> MisoString Source #

Route pretty printing

dumpURI :: route -> MisoString Source #

Route debugging

toRoute :: MisoString -> Either RoutingError route Source #

Route parsing from a MisoString

routeParser :: RouteParser route Source #

default routeParser :: (Generic route, GRouter (Rep route)) => RouteParser route Source #

type RouteParser = ParserT URI [Token] [] Source #

State monad for parsing URI

class GRouter (f :: k -> Type) where Source #

Generic deriving for Router

Methods

gFromRoute :: forall (route :: k). f route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (f route) Source #

Instances

Instances details
GRouter (U1 :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). U1 route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (U1 route) Source #

(GRouter left, GRouter right) => GRouter (left :*: right :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). (left :*: right) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser ((left :*: right) route) Source #

(GRouter left, GRouter right) => GRouter (left :+: right :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). (left :+: right) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser ((left :+: right) route) Source #

(KnownSymbol name, GRouter next) => GRouter (C1 ('MetaCons name x y) next :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). C1 ('MetaCons name x y) next route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (C1 ('MetaCons name x y) next route) Source #

GRouter next => GRouter (D1 m next :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). D1 m next route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (D1 m next route) Source #

KnownSymbol frag => GRouter (K1 m (Fragment frag) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (Fragment frag) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (Fragment frag) route) Source #

KnownSymbol path => GRouter (K1 m (Path path) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (Path path) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (Path path) route) Source #

KnownSymbol flag => GRouter (K1 m (QueryFlag flag) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (QueryFlag flag) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (QueryFlag flag) route) Source #

(ToMisoString a, FromMisoString a, KnownSymbol param) => GRouter (K1 m (QueryParam param a) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (QueryParam param a) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (QueryParam param a) route) Source #

Router a => GRouter (K1 m a :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m a route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m a route) Source #

GRouter next => GRouter (S1 m next :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). S1 m next route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (S1 m next route) Source #

(FromMisoString a, ToMisoString a) => GRouter (K1 m (Capture sym a) :: k2 -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k2). K1 m (Capture sym a) route -> [Token] Source #

gRouteParser :: forall (route :: k2). RouteParser (K1 m (Capture sym a) route) Source #

Types

newtype Capture (sym :: k) a Source #

Type used for representing capture variables

Constructors

Capture a 

Instances

Instances details
(FromMisoString a, ToMisoString a) => GRouter (K1 m (Capture sym a) :: k2 -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k2). K1 m (Capture sym a) route -> [Token] Source #

gRouteParser :: forall (route :: k2). RouteParser (K1 m (Capture sym a) route) Source #

Show a => Show (Capture sym a) Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> Capture sym a -> ShowS #

show :: Capture sym a -> String #

showList :: [Capture sym a] -> ShowS #

Eq a => Eq (Capture sym a) Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: Capture sym a -> Capture sym a -> Bool #

(/=) :: Capture sym a -> Capture sym a -> Bool #

FromMisoString a => FromMisoString (Capture sym a) Source # 
Instance details

Defined in Miso.Router

ToMisoString a => ToMisoString (Capture sym a) Source # 
Instance details

Defined in Miso.Router

newtype Path (path :: Symbol) Source #

Type used for representing URL paths

Constructors

Path MisoString 

Instances

Instances details
KnownSymbol path => GRouter (K1 m (Path path) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (Path path) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (Path path) route) Source #

IsString (Path path) Source # 
Instance details

Defined in Miso.Router

Methods

fromString :: String -> Path path #

Show (Path path) Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> Path path -> ShowS #

show :: Path path -> String #

showList :: [Path path] -> ShowS #

Eq (Path path) Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: Path path -> Path path -> Bool #

(/=) :: Path path -> Path path -> Bool #

ToMisoString (Path path) Source # 
Instance details

Defined in Miso.Router

Methods

toMisoString :: Path path -> MisoString Source #

newtype QueryParam (path :: Symbol) a Source #

Type used for representing query parameters

Constructors

QueryParam (Maybe a) 

Instances

Instances details
(ToMisoString a, FromMisoString a, KnownSymbol param) => GRouter (K1 m (QueryParam param a) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (QueryParam param a) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (QueryParam param a) route) Source #

Show a => Show (QueryParam path a) Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> QueryParam path a -> ShowS #

show :: QueryParam path a -> String #

showList :: [QueryParam path a] -> ShowS #

Eq a => Eq (QueryParam path a) Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: QueryParam path a -> QueryParam path a -> Bool #

(/=) :: QueryParam path a -> QueryParam path a -> Bool #

(FromMisoString a, KnownSymbol path) => FromMisoString (QueryParam path a) Source # 
Instance details

Defined in Miso.Router

(ToMisoString a, KnownSymbol path) => ToMisoString (QueryParam path a) Source # 
Instance details

Defined in Miso.Router

newtype QueryFlag (path :: Symbol) Source #

Type used for representing query flags

Constructors

QueryFlag Bool 

Instances

Instances details
KnownSymbol flag => GRouter (K1 m (QueryFlag flag) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (QueryFlag flag) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (QueryFlag flag) route) Source #

Show (QueryFlag path) Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> QueryFlag path -> ShowS #

show :: QueryFlag path -> String #

showList :: [QueryFlag path] -> ShowS #

Eq (QueryFlag path) Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: QueryFlag path -> QueryFlag path -> Bool #

(/=) :: QueryFlag path -> QueryFlag path -> Bool #

KnownSymbol name => ToMisoString (QueryFlag name) Source # 
Instance details

Defined in Miso.Router

data Fragment (path :: Symbol) Source #

Type used for representing fragments

Constructors

Fragment 

Instances

Instances details
KnownSymbol frag => GRouter (K1 m (Fragment frag) :: k -> Type) Source # 
Instance details

Defined in Miso.Router

Methods

gFromRoute :: forall (route :: k). K1 m (Fragment frag) route -> [Token] Source #

gRouteParser :: forall (route :: k). RouteParser (K1 m (Fragment frag) route) Source #

Show (Fragment path) Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> Fragment path -> ShowS #

show :: Fragment path -> String #

showList :: [Fragment path] -> ShowS #

Eq (Fragment path) Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: Fragment path -> Fragment path -> Bool #

(/=) :: Fragment path -> Fragment path -> Bool #

KnownSymbol frag => ToMisoString (Fragment frag) Source # 
Instance details

Defined in Miso.Router

data Token Source #

A list of tokens are returned from a successful lex of a URI

Instances

Instances details
Show Token Source # 
Instance details

Defined in Miso.Router

Methods

showsPrec :: Int -> Token -> ShowS #

show :: Token -> String #

showList :: [Token] -> ShowS #

Eq Token Source # 
Instance details

Defined in Miso.Router

Methods

(==) :: Token -> Token -> Bool #

(/=) :: Token -> Token -> Bool #

ToMisoString Token Source # 
Instance details

Defined in Miso.Router

data URI Source #

URI type. See the official specification

Constructors

URI 

Fields

Instances

Instances details
Generic URI Source # 
Instance details

Defined in Miso.Types

Associated Types

type Rep URI 
Instance details

Defined in Miso.Types

Methods

from :: URI -> Rep URI x #

to :: Rep URI x -> URI #

Show URI Source # 
Instance details

Defined in Miso.Types

Methods

showsPrec :: Int -> URI -> ShowS #

show :: URI -> String #

showList :: [URI] -> ShowS #

Eq URI Source # 
Instance details

Defined in Miso.Types

Methods

(==) :: URI -> URI -> Bool #

(/=) :: URI -> URI -> Bool #

ToJSVal URI Source # 
Instance details

Defined in Miso.Types

Methods

toJSVal :: URI -> IO JSVal Source #

ToObject URI Source # 
Instance details

Defined in Miso.Types

Methods

toObject :: URI -> IO Object Source #

FromJSON URI Source # 
Instance details

Defined in Miso.Router

ToJSON URI Source # 
Instance details

Defined in Miso.Types

Methods

toJSON :: URI -> Value Source #

toJSONList :: [URI] -> Value

FromMisoString URI Source # 
Instance details

Defined in Miso.Router

ToMisoString URI Source # 
Instance details

Defined in Miso.Types

type Rep URI Source # 
Instance details

Defined in Miso.Types

Errors

data RoutingError Source #

An error that can occur during lexing / parsing of a URI into a user-defined data type

Instances

Instances details
Show RoutingError Source # 
Instance details

Defined in Miso.Router

Eq RoutingError Source # 
Instance details

Defined in Miso.Router

Functions

prettyURI :: URI -> MisoString Source #

Pretty-prints a URI.

prettyQueryString :: URI -> MisoString Source #

Pretty-prints a URI query string.

Manual Routing

runRouter Source #

Arguments

:: MisoString

The raw URL string to parse

-> RouteParser route

Parser to apply against the tokenised URL

-> Either RoutingError route 

Smart constructor for building a RouteParser

data Route = Widget MisoString Int

instance Router Route where
  routeParser = routes [ Widget <$> path "widget" <*> capture ]
  fromRoute (Widget path value) = [ toPath path, toCapture value ]

router :: Router router => RouteParser router
router = routes [ Widget <$> path "widget" <*> capture ]

> Right (Widget "widget" 10)

routes :: [RouteParser route] -> RouteParser route Source #

Convenience for specifying multiple routes

Construction

toQueryParam Source #

Arguments

:: ToMisoString s 
=> MisoString

Query parameter key

-> s

Query parameter value

-> Token 

Smart constructor for building a QueryParamToken

toCapture :: ToMisoString string => string -> Token Source #

Smart constructor for building a capture variable

toPath :: MisoString -> Token Source #

Smart constructor for building a path fragment

Parser combinators

queryFlag :: forall (flag :: Symbol). KnownSymbol flag => RouteParser (QueryFlag flag) Source #

Query flag parser from a route

queryParam :: forall (param :: Symbol) a. (FromMisoString a, KnownSymbol param) => RouteParser (QueryParam param a) Source #

Query parameter parser from a route

capture :: FromMisoString value => RouteParser value Source #

Combinator for parsing a capture variable out of a URI

path :: MisoString -> RouteParser MisoString Source #

Combinator for parsing a path out of a URI

Lexing

tokensToURI :: [Token] -> URI Source #

Converts a list of [Token] into an actual URI.

Orphan instances

FromJSON URI Source # 
Instance details

FromMisoString URI Source # 
Instance details