Review Board 1.5.4

Issue 457 -- add REST helpers to Lift

Updated 1 year, 9 months ago

David Pollak Reviewers
dpp, timperrett, marius, charles, heiko, joni, atsuhiko, jorge, naftoli, kris, indrajit, alexb, dlouwers, mstarzyk, rmellgren, jhoffman, probinett, jmadsen, mhartmann, jstrachan, jgoday
None LiftWeb-archive
https://liftweb.assembla.com/spaces/liftweb/tickets/457-enhanced-rest-wrapper#last_comment

dpp_issue_457

Added some REST helpers to Lift.

See https://liftweb.assembla.com/spaces/liftweb/wiki?id=liftweb&wiki_id=REST_Web_Services for examples
Updated the ws example to use the new code and did smoke tests
Posted 1 year, 9 months ago (April 27th, 2010, 1:45 a.m.)
Can we have extractors like:

 def unapply(r: Req): Option[(List[String], Req, List[(String, String)])] ?

so that one can pattern match by HTTP header fields as well ?
  1. I said it's not possible to pattern match against the headers in this thread: http://groups.google.com/group/liftweb/browse_thread/thread/474b3e768ea1c949/e7f8036e3b40d51e?hl=en&lnk=gst&q=accept#e7f8036e3b40d51e  and then again in this thread: http://groups.google.com/group/liftweb/browse_thread/thread/b00185cec49a167/8d4d5f22fd7d0de7?hl=en&lnk=gst&q=accept#8d4d5f22fd7d0de7
    
    Have I not made the technical issues clear?
    
    
  2. As an interesting footnote, it is possible to pull out a particular header, but it's not clean. You have to bump through a stable identifier first:
    
    scala> object header {
         |   def apply(which: String): HeaderExtractor = new HeaderExtractor(which)
         |   class HeaderExtractor(which: String) {
         |     def unapply(in: List[(String, Any)]): Option[Any] = in.find(_._1 == which)
         |   }
         | }
    defined module header
    
    scala> val x = header("Boo")
    x: header.HeaderExtractor = header$HeaderExtractor@272b72f4
    
    scala> val y = ("Foo", 1)::("Bar", 2)::("Boo", 3)::Nil
    y: List[(java.lang.String, Int)] = List((Foo,1), (Bar,2), (Boo,3))
    
    scala> y match { case x(a) => a; case _ => "no idea" } 
    res1: Any = (Boo,3)
    
    I don't mean to comment on the REST feature, just thought it might be interesting that you can do this.
  3. Yes, it's possible to write a custom extractor and it's possible to write code that vends custom extractors.  But in the case you gave, there's no way to chain the extraction:
    
    val accept = header("Accept")
    val contentType = header("Content-Type")
    
    list match {
      case accept("text/xml") :: contentType("text/xml") =>
    }
    
    And even if it were, you'd need a second extractor to test against "text/xml" because it could be "text/xml", "TEXT/XML" or "text/xml; charset=utf-8", etc.
    
    Until there are language level curried extractors (basically building the extractor in the pattern based on parameters to the extractor), there's no savings to try to pattern match across an unordered List[String -> String], Map[String, String], etc.
    
    Put another way, if you're going to go through the effort to build an extractor, you can compose your own extractor the same way RestHelper does it:  lazy val MyExtractor = new TestGet with MyHeaderMatcher  where you write imperative code to determine if the headers match correctly.
    
Ship it!
Posted 1 year, 9 months ago (April 27th, 2010, 10:19 a.m.)