14 March 2011

跟所有Lift的feature一样,支持REST也是非常非常得简单。

Mixin这个trait:

1
object AdminAPI extends RestHelper

Boot.scala里面加上:

1
LiftRules.dispatch.append(AdminAPI)

如果不需要创建session(不创建著名的S对象),还可以:

1
LiftRules.statelessDispatchTable.append(AdminAPI)

然后就是URL匹配:

1
2
3
4
5
6
serve {
  case "api" :: "add" :: Nil JsonGet _ => add
  case "api" :: "delete" :: Nil JsonGet _ => delete
  case "api" :: "edit" :: Nil JsonGet _ => edit
  case "api" :: "get" :: Nil JsonGet _ => get
}

以上都是GET的JSON接口。JsonGet会检查HTTP头里面的Accept以确认client是否支持JSON,这里需要注意的是“*/*”表示所有都接受(这个应该已经在2.3里面被修复掉了);当然如果Accept里面不支持JSON,JsonGet还会去查询URL是否是.json结尾。

具体解释一下上面的例子。

对于URL为 http://server/api/add.json 的请求,第一条匹配规则命中,最后那个“_”是Req,然后调用add方法,add的返回值需要是LiftResponse类型;其实LiftReponse是个啥都不干的trait,有很多实现,JsonResponse、XmlResponse等等,总之几乎不用特别在意,Lift里面能作为response返回给client的都能用。

其他的匹配类似处理。

给个add方法的实现:

1
2
3
4
5
6
7
8
9
10
11
12
private def add = {
  val linkId = param(ShortenedUrl.originUrl.name).map(x => {
    shortenedUrl.find(ShortenedUrl.originUrl.name -> x).map(_.linkId.value) or {
      val tmp = (DependencyFactory.inject[NextIdGenerator].open_! !? 'id).toString
      shortenedUrl.createRecord.linkId(tmp).originUrl(x).shortUrl(Props.get(Site).open_! + "/" + tmp).date(new Date).
              ip(containerRequest.map(_.remoteAddress).toString).clickCount(0).save
      Full(tmp)
    }
  })
  (StatusField -> linkId.map(_.map(x => SuccessStatus)).openOr(Full(FailedStatus)).openOr(FailedStatus)) ~
          (ShortenedUrl.linkId.name -> linkId.openOr(Full("")).openOr(""))
}

返回一个JSON对象{status: “successful”, linkId: “1″}。

Lift利用Scala对DSL的支持把JSON整得很舒服,几乎跟js原生的用起来没区别:

1
2
3
("name" -> "honnix") ~
  ("address" -> "somewhere") ~
    ("phone" -> List("111", "222", "333"))

等价于:

1
2
3
{name: "honnix",
 address: "somewhere",
 phone: ["111", "222", "333"]}

具爽吧?



blog comments powered by Disqus