Table of contents
1.
Introduction
2.
String Interpolating Routing DSL
2.1.
Binding sird Router
2.1.1.
Using the SIRD router from a routes file
2.1.2.
Composing SIRD routers
2.1.3.
Providing a DI router
2.1.4.
Providing a DI router with Guice
3.
Javascript Routing
3.1.
Generating a Javascript router
3.1.1.
Embedded router
3.1.2.
Router resource
3.2.
Using the router
4.
Custom Routing
4.1.
PathBindable
4.2.
QueryStringBindable
5.
Frequently Asked Questions
5.1.
What is Scala?
5.2.
What exactly is Scala Framework?
5.3.
What do you mean by Rails with Scala?
5.4.
What exactly does a Scala developer do?
5.5.
Does Scala outperform Java? 
6.
Conclusion
Last Updated: Mar 27, 2024
Medium

Scala developers-Advanced routing for Scala

Author Manan Singhal
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Scala is a computer language for creating robust static systems and functional programs. It is JVM-based and object-oriented. It is capable of interacting with libraries and existing Java programs. The idea of primitive data is absent. Thus it is widely believed to be a static type of  language.

Learn Scala

String Interpolating Routing DSL

Binding sird Router

There are various ways to configure an application to use a sird Router:

Using the SIRD router from a routes file

Extend the SimpleRouter to integrate the routing DSL with a typical Play project that uses a routes file and controllers:

package api

import javax.inject.Inject
import play.api.mvc._
import play.api.routing.Router.Routes
import play.api.routing.SimpleRouter
import play.api.routing.sird._

class ApiRouter @Inject() (controller: ApiController) extends SimpleRouter {
  override def routes: Routes = {
    case GET(p"/") => controller.index
  }
}
You can also try this code with Online Java Compiler
Run Code

 

Composing SIRD routers

Since routes are only partial functions, you can combine numerous routers. To compose your routes in an application router later, you can divide your routes into smaller, more specialized routers. For instance, taking into account the SinglePageApplicationRouter and the ApiRouter already mentioned:

class SpaRouter @Inject() (controller: SinglePageApplicationController) extends SimpleRouter {
  override def routes: Routes = {
    case GET(p"/api") => controller.api
  }
}
You can also try this code with Online Java Compiler
Run Code


Then, you can combine the two to create a full router for your application

class AppRouter @Inject() (spaRouter: SpaRouter, apiRouter: ApiRouter) extends SimpleRouter {
  // Composes both routers with spaRouter having precedence.
  override def routes: Routes = spaRouter.routes.orElse(apiRouter.routes)
}
You can also try this code with Online Java Compiler
Run Code
Team

Providing a DI router

class SirdAppLoader extends ApplicationLoader {
  def load(context: Context) = {
    new SirdComponents(context).application
  }
}

class SirdComponents(context: Context) extends BuiltInComponentsFromContext(context) with NoHttpFiltersComponents {
  lazy val router = Router.from {
    case GET(p"/hello/$to") =>
      Action {
        Ok(s"Hello $to")
      }
  }
}
You can also try this code with Online Java Compiler
Run Code

 

Providing a DI router with Guice

class ScalaSimpleRouter @Inject() (val Action: DefaultActionBuilder) extends SimpleRouter {
  override def routes: Routes = {
    case GET(p"/") =>
      Action {
        Results.Ok
      }
  }
}

@Singleton
class ScalaRoutesProvider @Inject() (playSimpleRouter: ScalaSimpleRouter, httpConfig: HttpConfiguration)
    extends Provider[Router] {
  lazy val get = playSimpleRouter.withPrefix(httpConfig.context)
}

class ScalaGuiceAppLoader extends GuiceApplicationLoader {
  protected override def overrides(context: ApplicationLoader.Context): Seq[GuiceableModule] = {
    super.overrides(context) :+ (bind[Router].toProvider[ScalaRoutesProvider]: GuiceableModule)
  }
}
You can also try this code with Online Java Compiler
Run Code

Javascript Routing

Javascript

To manage routing from Javascript that is running client-side back to your application, the play router can produce Javascript code. Refactoring your application is made more accessible by the Javascript router. Your Javascript is immediately updated to reflect the new structure if you modify the URL or parameter name structure.

Generating a Javascript router

The generation of Play's Javascript router is the initial step in using it. To reduce the amount of the Javascript code, the router will only expose the routes you expressly designate.

A Javascript router can be created in two different methods. One is to use template directives to incorporate the router within the HTML page. The alternative is to generate Javascript assets through a process that may be downloaded, cached and shared between pages.

Embedded router

The @javascriptRouter directive inside a Scala template can create an embedded router. Usually, this is carried out within the main decorative template.

@()(implicit req: play.api.mvc.RequestHeader)

@helper.javascriptRouter("jsRoutes")(
    routes.javascript.Users.list,
    routes.javascript.Users.get
)

 

The first option specifies the name of the global variable in which the router will be stored (routes.javascript.Users.list, routes.javascript.Users.get). The second option is the list of Javascript routes that should be added to this router. From the above example, your template must have an implicit RequestHeader in scope to use this function.

Router resource

A router resource may be generated by developing an action that uses the router generator. The syntax is the same as when the router is embedded in a template:

import javax.inject.Inject
import play.api.http.MimeTypes
import play.api.mvc._
import play.api.routing._

 

def javascriptRoutes = Action { implicit request =>
  Ok(
    JavaScriptReverseRouter("jsRoutes")(
      routes.javascript.Users.list,
      routes.javascript.Users.get
    )
  ).as(MimeTypes.JAVASCRIPT)
}
Thinking

Using the router

Making a call is easy, for instance, using jQuery:

$.ajax(jsRoutes.controllers.Users.get(someId))
  .done( /*...*/ )
  .fail( /*...*/ );


Other attributes made available by the router include the type and the url (the HTTP method). For instance, the ajax function call made in the example above can also be made as follows:

var r = jsRoutes.controllers.Users.get(someId);
$.ajax({url: r.url, type: r.type, success: /*...*/, error: /*...*/ });


When other properties, such as success, error, context, etc., need to be set, the strategy above is necessary.

The entire url string is returned via the methods (not properties) absoluteURL and webSocketURL. Creating a Websocket connection looks like this:

var r = jsRoutes.controllers.Users.list();
var ws = new WebSocket(r.webSocketURL());
ws.onmessage = function(msg) {
        /*...*/
};

Custom Routing

Routing

PathBindable

PathBindable enables the binding of business objects from the URL path; as a result, we may construct routes like /user/1 to invoke the following action:

def user(user: User) = Action {
  Ok(user.name)
}


An easy illustration of the binder using the :id path parameter:

implicit def pathBinder(implicit intBinder: PathBindable[Int]) = new PathBindable[User] {
  override def bind(key: String, value: String): Either[String, User] = {
    for {
      id   <- intBinder.bind(key, value).right
      user <- User.findById(id).toRight("User not found").right
    } yield user
  }
  override def unbind(key: String, user: User): String = {
    user.id.toString
  }
}


In this example, the findById method is used to retrieve the User instance; however, in the real world, findById methods should be lightweight and avoid using database access, for example, since they are executed on the server's IO thread and must be completely non-blocking.

As a result, you might, for instance, utilize simple object identifiers as path bindable and use action composition to get the actual values.

QueryStringBindable

For query string arguments, a similar method is employed; a route like /age can be built to invoke an operation like

def age(age: AgeRange) = Action {
  Ok(age.from.toString)
}


An easy case of the:from and:to query string parameters being bound by the binder:

implicit def queryStringBindable(implicit intBinder: QueryStringBindable[Int]) = new QueryStringBindable[AgeRange] {
  override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, AgeRange]] = {
    for {
      from <- intBinder.bind("from", params)
      to   <- intBinder.bind("to", params)
    } yield {
      (from, to) match {
        case (Right(from), Right(to)) => Right(AgeRange(from, to))
        case _                        => Left("Unable to bind an AgeRange")
      }
    }
  }
  override def unbind(key: String, ageRange: AgeRange): String = {
    intBinder.unbind("from", ageRange.from) + "&" + intBinder.unbind("to", ageRange.to)
  }
}

 

All the binders that Play offers automatically apply form URL encoding in their unbind methods, safely encoding all special characters.

Frequently Asked Questions

What is Scala?

Scala is an open-source, general purpose, multiple paradigm programming language. It supports both functional and object-oriented programming principles.

What exactly is Scala Framework?

Ruby software includes the Scala domain-specific language and the web application library. Instead of Ruby on Rails, Merb, Nitro, and Camping, it uses a Ruby web application framework called Camping. It depends on the Rack web server interface. As a mark of respect, it carries Frank Scala's name.

What do you mean by Rails with Scala?

In contrast to Rails, a framework for creating model-driven online applications, Scala is a server-side HTTP library. If you think of HTTP requests and responses, Scala is the finest tool. If you need complete integration with the least amount of boilerplate possible, Rails is the way to go.

What exactly does a Scala developer do?

A Scala developer is responsible for designing,  developing, and managing scala-based web applications. They should be familiar with the concepts of Scala knowledge, including but not limited to functional and object-oriented programming paradigms.

Does Scala outperform Java? 

According to the study, Scala is quicker than Java and Go when typical developers write code without much thought to optimization. The study took advantage of each language's standard, idiomatic data structures.

Conclusion

This article taught us advanced routing for scala. I hope you would have gained a better understanding of these topics now!

If you want to learn more about CherryPy topics, follow the link given below:

Refer to our guided paths on Coding Ninjas Studio to learn about Data Structure and Algorithms, Competitive Programming, JavaScript, etc. Enroll in our courses and refer to our mock test available. Have a look at the interview experiences and interview bundle for placement preparations.

Please upvote our blog to help other ninjas grow.

Happy Learning!

Live masterclass