How to represent optional fields in spray-json?

You might have to create an explicit format (warning: psuedocodish):

object SearchRequestJsonProtocol extends DefaultJsonProtocol {
    implicit object SearchRequestJsonFormat extends JsonFormat[SearchRequest] {
        def read(value: JsValue) = value match {
            case JsObject(List(
                    JsField("url", JsString(url)),
                    JsField("nextAt", JsString(nextAt)))) =>
                SearchRequest(url, Some(new Instant(nextAt)))

            case JsObject(List(JsField("url", JsString(url)))) =>
                SearchRequest(url, None)

            case _ =>
                throw new DeserializationException("SearchRequest expected")
        }

        def write(obj: SearchRequest) = obj.nextAt match {
            case Some(nextAt) => 
                JsObject(JsField("url", JsString(obj.url)),
                         JsField("nextAt", JsString(nextAt.toString)))
            case None => JsObject(JsField("url", JsString(obj.url)))
        }
    }
}

Works for me (spray-json 1.1.1 scala 2.9.1 build)

import cc.spray.json._
import cc.spray.json.DefaultJsonProtocol._

// string instead of date for simplicity
case class SearchRequest(url: String, nextAt: Option[String])

// btw, you could use jsonFormat2 method here
implicit val searchRequestFormat = jsonFormat(SearchRequest, "url", "nextAt")

assert {
  List(
    """{"url":"..."}""",
    """{"url":"...", "nextAt":null}""",
    """{"url":"...", "nextAt":"2012-05-30T15:23Z"}""")
  .map(_.asJson.convertTo[SearchRequest]) == List(
    SearchRequest("...", None),
    SearchRequest("...", None),
    SearchRequest("...", Some("2012-05-30T15:23Z")))
}