wix-incubator / accord

Accord: A sane validation library for Scala
http://wix.github.io/accord/
Other
529 stars 55 forks source link

Can't find example with web data #72

Closed francois closed 8 years ago

francois commented 8 years ago

I'm in the context of a Jetty Handler. I retrieve the query parameters using Option(request.getParameter("q")), and would like to validate that the q parameter is not empty. Here's what I have coded so far:

case class SearchForm(q: Option[String])

object SearchForm {
  implicit val searchFormValidator = validator[SearchForm] { form =>
    form.q is notEmpty
  }
}

// in the Jetty handler
import SearchForm._
val query = SearchForAccountForm(Option(request.getParameter("q")))
validate(query) match {
    case com.wix.accord.Success =>
        // run the query and return results

    case com.wix.accord.Failure(violations) =>
        // return a JSON representation of the errors
}

Given the above, there are three cases I'm testing for: the q parameter is not provided, the q parameter is provided, but is empty, and the last case is the successful case:

# Great, exactly what I wanted!
$ curl -s http://localhost:8080/api/accounts/search
{
  "errors" : [ "q must not be empty" ]
}

# A JSON object with data means the request was accepted!
$ curl -s http://localhost:8080/api/accounts/search\?q\=
{
  "data" : [ ]
}

# This is the expected result, since no accounts have a 1 in their names
$ curl -s http://localhost:8080/api/accounts/search\?q\=1
{
  "data" : [ ]
}

What I wish happened is for Accord to already have a validator for required Option elements. I can write my own validator that fails on None and runs other validations on Some.

After writing the above, I ran a test where I directly used String instead of Option[String]. This worked better, but I have the feeling this is less type-safe. The results were:

# Not quite what I wanted, but it works for now
$ curl -s http://localhost:8080/api/accounts/search
{
  "errors" : [ "q is a null" ]
}

$ curl -s http://localhost:8080/api/accounts/search\?q\=
{
  "errors" : [ "q must not be empty" ]
}

$ curl -s http://localhost:8080/api/accounts/search\?q\=1
{
  "data" : [ ]
}

Are there already Accord extensions for Option elements? Should I write validators for Option values?

holograph commented 8 years ago

Hi @francois, I'm happy that you're trying out Accord :-)

To your question, you're actually defining two separate rules: the container (i.e. Option) must have a value, and the value itself must not be empty. One way to accomplish this (you can find additional examples in the DSL documentation):

case class SearchForm(q: Option[String])

object SearchForm {
  implicit val searchFormValidator = validator[SearchForm] { form =>
    form.q is notEmpty         // Validates the container
    form.q.each is notEmpty    // Validates the value
  }
}

Let me know if this works for you, or if you have some ideas on how to improve the docs.

As an aside, this makes me think that maybe additional collection-like combinators might apply (e.g. any or once). If this seems useful, feel free to open a feature request :-)

francois commented 8 years ago

Wow, this page is gold! I never found it! Where is it linked from? Oh, just found it... It's the first word in the example section. I was looking for a standard navbar, either at the top or bottom of the page. Thanks for the help!

holograph commented 8 years ago

Yeah, unfortunately I've tried (and failed) a couple times to learn enough CSS to add a navbar. I guess I'll hunt down a front-end dev and sort it out :-)

francois commented 8 years ago

PR #73 adds navigation buttons for the two pages I did not find. See them on my fork: http://francois.github.io/accord/. Cheers!