The IsRoute typeclass is used to mainly define a Route Prism-based encoding for your route types. In other words, deriving IsRoute for the example route,

Example route
-- An example of nested routes
-- Route's expected encoding is given as a comment.

data Route
  = Route_Index          -- index.html
  | Route_About          -- about.html
  | Route_Contact        -- contact.html
  | Route_Blog BlogRoute -- blog/<BlogRoute>

data BlogRoute
  = BlogRoute_Index      -- index.html
  | BlogRoute_Post Slug  -- post/<Slug>

newtype Slug = Slug { unSlug :: String }

enables us to convert between Route_Blog BlogRoute_Index and /blog/index.html and vice versa (as shown in the tutorial).


IsRoute is defined as:

class IsRoute r where
  -- (1)
  type RouteModel r :: Type
  -- (2)
  routePrism :: RouteModel r -> Prism_ FilePath r
  -- (3)
  routeUniverse :: RouteModel r -> [r]
  • RouteModel is (optionally) used to specify the value that is used for encoding routes (as defined by routePrism).
    • For the blog route example above, this maybe be a type that contains your blog posts. It can also be () if you do not care about it.
  • routePrism gives us an optics prism (see Route Prism) that can be used to encode and decode between the route type and the .html filepath.
  • routeUniverse simply returns a list of routes to statically generate.

Generic deriving

IsRoute may be derived genericallly; see Generic deriving.

Links to this page
  • Upgrading
    Extract encodeRoute and decodeRoute (of Ema instance) into an IsRoute instance.
  • Route type

    An Ema app is defined by its route type. All routes must be an instance of the IsRoute class, which provides a route encoder (see Route Prism) that is used to convert to and from the corresponding .html filepaths. This instance can be hand-written or derived generically.

  • Route Prism

    Deriving IsRoute for our route types gives us a routePrism function that returns (effectively*) a Prism' FilePath r (from optics-core Prism') that in turn can be used to encode and decode route values to and from URLs or filepaths.

    Here is a naive implementation of IsRoute for the BlogRoute above:

  • Model type
    RouteModel of IsRoute associates a route type with a model type. This enables Route Prism (and routeUniverse) to accept that model value as an argument.

    A “model”, in an Ema app, represents all the data used to render the site. The model is also used (in IsRoute), optionally, to encode the route types.

  • Live Server

    It is not unusual to write Ema apps purely for the live server UX, and disable static site generation entirely (by nullifying routeUniverse in IsRoute).

  • Guide
    Derive IsRoute for it
  • Generic deriving

    IsRoute can be derived generically using DerivingVia.

  • Composing Ema apps

    The composition happens via sub-route composition. i.e., the Route type of your larger Ema app can contain the sub-route type in its sum constructors. If the sub-routes have IsRoute and EmaSite instances, then the corresponding instances for the larger route can be defined in terms of them.