Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign router #19

Open
tindzk opened this issue Oct 14, 2014 · 1 comment
Open

Redesign router #19

tindzk opened this issue Oct 14, 2014 · 1 comment

Comments

@tindzk
Copy link
Contributor

tindzk commented Oct 14, 2014

Currently, the router is designed in a similar fashion as in most dynamically-typed languages and therefore makes some compromises. We could better leverage Scala's type system for a more sophisticated design. The exact details still have to be worked out, but here's a sketch of what I think we should be heading to:

  • For performance reasons, a page should only be constructed once it is loaded and destroyed when the page changes.
    Right now, pages are instantiated lazily, but never destroyed.
  • There should be type-safe matchers such as StrArg, IntArg and the like. The user may want to define own matchers as well.
    Right now, every argument is a string and needs to be converted manually.
  • Channel-awareness: The idea is to be consistent with the rest of the Widok ecosystem.
    • The current route should be stored in a channel.
      This allows for better composability; as of now, a route change re-renders the whole page. This is not always desired. Sometimes only a certain part of the page should be replaced. An example are Bootstrap pages which are usually composed of a header, body and a footer. There it makes sense to update only the body upon page change. Thanks to channels, the header does not even have to be static. It could reside in an object providing channels which pages could send data to.
    • Arguments should be stored in a channel.
      Instead of reloading the whole page, the page is constantly getting notified about changing argument(s). As channels already provide unique, this should be easy to implement. Then, it only re-renders those parts which are actually related to the changed argument.
  • Store templates in variables, not in methods.
  • Deprecate Seq-to-Widget implicit.
object Routes {
    import Route._
    val enabled = Set(
        Route[MainPage](),
        Route[ArticlePage]("article" / StrArg),
        Route[ArticlePage]("article"),
        Route[BookPage]("book" / IntArg)
    )
}

object Partials {
    val header = Bootstrap.NavigationBar(...)
    val body = HTML.Container.Generic(...)
    val footer = Bootstrap.Footer(...)

    val layout = HTML.Container.Generic(header, body, footer)
}

class Main extends Application {
    def render(route: Channel[Route]) = {
        Partials.body.bindWidget(route.map(_.create().contents))
        Partials.layout
    }
}

case class ArticlePage(artId: Channel[String] = Channel()) extends Page
case class BookPage(bookId: Channel[Int] = Channel()) extends Page

// ---

object Route {
    case object IntArg extends Matcher { }
    case object StrArg extends Matcher { }
    def apply[T](args: HList) { }
}

trait Route {
    def create(): Page
}

trait Page {
    val contents: Widget[_]
}

trait Application {
    def render(route: Channel[Route]): Widget[_]
}

I guess, it would be hard to come up with a solution that doesn't make use of macros even if were to use Shapeless.

In general, the design comes close to what Spray already does and I'd suggest we take some inspiration from there: https://github.com/spray/spray/blob/master/spray-routing/src/main/scala/spray/routing/PathMatcher.scala

A similar concept can be found in this Haskell library: http://hackage.haskell.org/package/web-routes-boomerang-0.28.3/docs/Web-Routes-Boomerang.html

@tindzk tindzk added this to the v0.2 milestone Oct 14, 2014
@tindzk tindzk modified the milestones: v0.3, v0.2 Feb 1, 2015
@jn73
Copy link
Contributor

jn73 commented May 31, 2015

It would also be nice with support for trailing request params in the new router (and current if easily implemented). To support paths like:

#/users/:userId?filter=name&template=default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants