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

Provide URI and URI template of a route definition #8

Closed
arouel opened this issue Jul 4, 2014 · 2 comments
Closed

Provide URI and URI template of a route definition #8

arouel opened this issue Jul 4, 2014 · 2 comments

Comments

@arouel
Copy link
Contributor

arouel commented Jul 4, 2014

Specifications that can be used to self describe (e.g. Swagger, JSON HAL) web services use URI RFC3986 and URI Template RFC6570 often.

It would be helpful be able to transform a route definition into a URI or URI Template. For example, this would lower the amount of redundant code when working with JSON HAL to describe references to other resources within a specific resource.

object MyWebService {

  val startParam = query[Int]("start", 0)
  val limitParam = query[Int]("limit", 0)
  val orders = GET / "orders"
  val ordersSearch = GET / "orders" +? query[String]("searchterm")
  val ordersPaginated = orders +? startParam & limitParam
  val order = orders / pathVar[Int]
  val orderItems = orders / pathVar[Int] / "items" +? startParam & limitParam

  // what we can do today
  val service1 = new RhoService {
    ordersPaginated |>> { (start: Int, limit: Int) =>
      "return page of orders"
    }
    order |>> { id: Int =>
      s"return order with id $id"
    }
    orderItems |>> { (id: Int, start: Int, limit: Int) =>
      s"return page of items from order with id $id"
    }
  }

  // what we need for JSON HAL
  val service2 = new RhoService {
    ordersPaginated |>> { (start: Int, limit: Int) =>
      ResourceObject[Map[String, Any]](
        Vector(
          "self" -> Single(LinkObject(self.toUri)), // self should be implicitly available
          "next" -> Single(LinkObject(orders.toUri +? startParam(start + limit))),
          "search" -> Single(LinkObject(ordersSearch.toUriTemplate))),
          Vector.empty,
          Some(Map("orders" -> List(1, 2, 3, 4, 5, 6, 7, 8, 9)))))
    }
    order |>> { id: Int =>
      ResourceObject[Map[String, Any]](
        Vector(
          "self" -> Single(LinkObject(self.toUri)), // self should be implicitly available
          "items" -> Single(LinkObject(orderItems(id).toUri))),
          Vector.empty,
          Some(Map("items" -> List(1, 2, 3, 4, 5, 6, 7, 8, 9))))
    }
    orderItems |>> { (id: Int, start: Int, limit: Int) =>
      ResourceObject[Map[String, Any]](
        Vector(
          "self" -> Single(LinkObject(orders.toUri)),
          "next" -> Single(LinkObject(orders.toUri +? startParam(start + limit)))),
          Vector.empty,
          Some(Map("items" -> List("concrete item 1", "concrete item 2" ... ))))
    }
  }

}
@arouel arouel changed the title Support URI and URI template in route definition and vice versa Provide URI and URI template of a route definition Jul 4, 2014
@bryce-anderson
Copy link
Member

+1. I think this should be doable, though the syntax may be a bit different particularly when using the dsl template as a function startParam(start + limit). We'll see what can be done.

@arouel
Copy link
Contributor Author

arouel commented Jul 4, 2014

A quick sketch how our model of an URI template in http4s could look like.

case class UriTemplate(
  scheme: Option[CaseInsensitiveString] = None,
  authority: Option[Authority] = None,
  path: Option[Path] = Some(Seq()),
  query: Option[Query] = None,
  fragment: Option[Fragment] = None) 

type Path = Seq[PathSegment]
sealed trait PathSegment
case class PathStatic(name: String, value: Option[String]) extends PathSegment
case class PathVar(name: String) extends PathSegment

type Query = Seq[QuerySegment]
sealed trait QuerySegment
case class Param(name: String, value: Seq[String]) extends QuerySegment
case class ParamExp(name: String) extends QuerySegment

type Fragment = Seq[FragmentSegment]
sealed trait FragmentSegment
case class FragmentStatic(name: String) extends FragmentSegment
case class FragmentExp(name: String) extends FragmentSegment

@arouel arouel closed this as completed Jul 9, 2014
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