Routes Matching 🔗
Routes matching design 🔗
Web frameworks do their routes matching with various mechanisms:
- annotation + method param: Spring and most other popular Java frameworks, Cask etc
- special route file DSL: PlayFramework, Ruby on Rails
- in-language DSL: zio-http, akka-http
- pattern matching: Sharaf, http4s
Why not annotations? 🔗
Let's see an example:
@GetMapping(value = "/student/{studentId}")
public Student studentData1(@PathVariable Integer studentId) {}
@GetMapping(value = "/student/{studentId}")
public Student studentData2(@PathVariable Integer studentId) {}
@GetMapping(value = "/student/umm")
public Student studentData3(@PathVariable Integer studentId) {}
Issues:
- the
studentId
appears in 2 places, you can make a typo and nothing will work. - the
"/student/{studentId}"
route is duplicated, there is no compiler support and it will fail only in runtime.. - you have to wonder if
studentData1
will be picked up beforestudentData3
..!?
Why not special route file? 🔗
Well, you need a special compiler for this, essentially a new language.
People have to learn how it works, there's probably no syntax highlighting, no autocomplete etc.
Why not in-language DSL? 🔗
Similar to special route file approach, people need to learn it.
And again, you don't leverage compiler's support like exhaustive pattern matching and extractors.
Sharaf's approach 🔗
Sharaf does its route matching in plain scala code.
Scala's pattern matching warns you when you have duplicate routes, or impossible routes.
For example, if you write this:
case GET -> Path("cars", brand) => ???
case GET -> Path("cars", model) => ??? // Unreachable case
case GET -> Path("files", segments*) => ???
case GET -> Path("files", "abc.txt") => ??? // Unreachable case
you will get nice warnings, thanks compiler!
You can extract path variables with pattern matching:
case GET -> Path("cars", param[Int](carId)) => ???
Here, the carId
is parsed as Int
and it mentioned only once, unlike with the annotation approach.