Skip to content
This repository has been archived by the owner on Oct 23, 2024. It is now read-only.

#2735 - replacement of ModelValidation #2804

Merged
merged 1 commit into from
Jan 11, 2016

Conversation

lxwbr
Copy link
Contributor

@lxwbr lxwbr commented Dec 9, 2015

@aquamatthias @kolloch @gkleiman @meichstedt Hey guys, we decided to give Accord Validation a try and replace our ModelValidation, which was still using Java's BeanValidation. The new library is capable of keeping track of the path down to the occurrence of the error. It is also using macros and detects property names automatically, so there is no need in propagating them explicitly. Validation rules can be constructed in an easy manner like this:

implicit val appDefinitionValidator = validator[V2AppDefinition] { appDef =>
    appDef.id is valid
    appDef.dependencies is valid
    appDef.upgradeStrategy is valid
    appDef.storeUrls is every(urlsCanBeResolvedValidator)
}

As it is an implicit validator, you could easily validate an appDefinition from type V2AppDefinition like this:

import mesosphere.marathon.api.v2.Validation._
...
validate(appDefintion)
...

We already tried the new validation out on some API methods. E.g. a following POST request in /v2/apps

{
  "id": "/test",
  "dependencies": ["-_","213","---_--_"]
}

will return an error sequence, which looks very similar to the one we are already used to:

{
  "errors": [
    {
      "attribute": "dependencies[0]",
      "error": "must match regular expression '^(([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])|(\\.|\\.\\.)$'"
    },
    {
      "attribute": "dependencies[2]",
      "error": "must match regular expression '^(([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])\\.)*([a-z0-9]|[a-z0-9][a-z0-9\\-]*[a-z0-9])|(\\.|\\.\\.)$'"
    }
  ]
} 

How do you feel about the new way of validating objects? You could have a look at e.g. AppsResource.scala in order to see the new validation in action.

@lxwbr lxwbr added the service label Dec 9, 2015
@lxwbr lxwbr self-assigned this Dec 9, 2015
new Validator[V2Group] {
override def apply(group: V2Group): Result = {
conf.maxApps.get.map { num =>
RuleViolation(group,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you compare num to the number of apps ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, you are right. I committed a change on that.

@aquamatthias
Copy link
Contributor

What do you think @kolloch @meichstedt @gkleiman ??

@kolloch
Copy link
Contributor

kolloch commented Dec 14, 2015

@Alexanderweber I just read your nice summary and it looks very good.

You say that the new error messages "look very similar". Does that mean they contain the same JSON fields in error responses, just that the messages are slightly different? We should only add fields to the JSON wherever possible to keep compatibility.

Furthermore, I would like to ensure that the following things are possible (I would expect it but better be certain). You don't have to address them at once in the patch, I am more interested in feasibility.

  • Error codes along with error messages: Currently, our error reporting sucks. I would much like to report an error code along with the error message. That could be the I18N text ID. It would also be nice to have a map of named arguments for the I18N template in the JSON, e.g.:
{
  "errors": [
    {
      "attribute": "dependencies.[0].path",
      "errorCode": "string.maxLengthExceeded", // just a silly example
      "errorArgs": {
          "value": "/this/is/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/long/for/a/path",
         "maxLength": 256
      },
      "error": "The value '/this/is/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/really/long/for/a/path' exceed the maximum length of 256 characters."
    }
  ]
}

That design allows automated parsing of errors and also allows (optionally) I18n by the frontend.

  • How can we make sure that the fieldNames in our messages correspond to field names in our JSON?
  • "Transforming" the error paths according to other API versions: We may have to support multiple API versions in the same code base that use different JSON attribute names or even a different structure.

@lxwbr
Copy link
Contributor Author

lxwbr commented Dec 14, 2015

@kolloch Hey Peter, I did mean exactly that - JSON field names will stay the same, but the content of messages might be slightly different.

  • I am not sure about the error codes at this point to be honest. Violation classes of the Accord framework expect Strings as error messages. I was actually talking to @aquamatthias about related topic: if we could match a violation against its type instead of the message string in our testing routines. An error code would do the job there. But I need to think about a possible realisation. As of this issue the feature is implemented in a separate branch, so there might be a i18n support in future releases.
  • The correspondence is provided by property names in validated classes. The framework figures out the property name through macros. As long as property names of the case class correspond to the JSON field names (which is the case as we are using play json, correct me if I am wrong), everything should correspond correctly.
  • That might be a problem, but I can still imagine it being possible, as field names can be explicitly be set during the validation as well.

@lxwbr lxwbr changed the title #2735 - replacement of ModelValidation. Still needs major testing. #2735 - replacement of ModelValidation Dec 14, 2015
@mwasn
Copy link

mwasn commented Dec 23, 2015

@kolloch Regarding error codes: The lack of error codes respectively missing documentation of those has actually been a demand of a customer. I´m going to create a separate story for implementation and documentation.

@lxwbr lxwbr assigned aquamatthias and unassigned lxwbr Jan 6, 2016
@lxwbr
Copy link
Contributor Author

lxwbr commented Jan 6, 2016

Merged master into this branch. Checks passed. @aquamatthias Please get back to me if you are ready to merge this pull request.

.getOrElse(Response.created(new URI(appId.toString)))
maybePostEvent(req, plan.target.app(appId).get)
deploymentResult(plan, response)
// TODO AW: test
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to remove comment or test?

@lxwbr
Copy link
Contributor Author

lxwbr commented Jan 7, 2016

@wendigo Nice to hear. Let me know if you'll have any issues using the new approach. I am hoping for a merge during today.

hc is validProtocol
}

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment here is:

  • outdated: since the problem with the seq is not valid any longer
  • in the wrong place: it probably should be moved to V2AppUpdate.appDefinitionValidator, where we don't do appDef.healthChecks is valid

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aquamatthias Regarding your second remark: do you mean the comment should be moved to appDefintionValidator? I did do so in c4cb9e2, it is now in V2AppDefinition.appDefinitionValidator.

@lxwbr lxwbr force-pushed the aw/wix-accord-generic-implicits branch from 45e0152 to de4fe79 Compare January 8, 2016 08:48
lxwbr pushed a commit that referenced this pull request Jan 8, 2016
@lxwbr lxwbr force-pushed the aw/wix-accord-generic-implicits branch from de4fe79 to 0affcaa Compare January 8, 2016 08:53
lxwbr pushed a commit that referenced this pull request Jan 8, 2016
@lxwbr lxwbr force-pushed the aw/wix-accord-generic-implicits branch from 0affcaa to c4cb9e2 Compare January 8, 2016 08:55
lxwbr pushed a commit that referenced this pull request Jan 8, 2016
@wendigo
Copy link
Contributor

wendigo commented Jan 8, 2016

@Alexanderweber sure thing!

@@ -1,234 +0,0 @@
package mesosphere.marathon.api.validation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @Alexanderweber sorry that I did not mention that before: why did you remove the whole test class here? Would it not make sense to use the new validation logic here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aquamatthias Sorry for late reply. As I was deleting the whole validation folder with annotation validation, I did not pay attention, that there was also one test included in there. Sorry for that, I added it back again adjusting it to new validation model. I need to merge the master into the branch again, I'll do so by the end of the day.

@lxwbr lxwbr force-pushed the aw/wix-accord-generic-implicits branch from c4cb9e2 to e910451 Compare January 11, 2016 11:20
lxwbr pushed a commit that referenced this pull request Jan 11, 2016
@aquamatthias
Copy link
Contributor

@Alexanderweber: Thanks. Please rebase.

@aquamatthias aquamatthias assigned lxwbr and unassigned aquamatthias Jan 11, 2016
@lxwbr lxwbr force-pushed the aw/wix-accord-generic-implicits branch from e910451 to f9b2daa Compare January 11, 2016 14:16
@lxwbr lxwbr assigned aquamatthias and unassigned lxwbr Jan 11, 2016
@aquamatthias
Copy link
Contributor

This is a great addition. Thanks!

aquamatthias added a commit that referenced this pull request Jan 11, 2016
@aquamatthias aquamatthias merged commit 1390579 into master Jan 11, 2016
@aquamatthias aquamatthias deleted the aw/wix-accord-generic-implicits branch January 11, 2016 14:55
@wendigo
Copy link
Contributor

wendigo commented Jan 11, 2016

Nice! :)

@holograph
Copy link

Hi everyone, sorry to raise the dead but I missed the original discussion when it was still ongoing. I'm the maintainer of Accord, and would absolutely love your input on how to add these features cleanly!

In particular, Accord is currently quite naïve about how it handles violations, in that it simply encodes them as strings. There's an open issue (wix-incubator/accord#21) that deals with the various implementation options, but lacking external input I was never sufficiently happy with any of them. It's a somewhat long-winded discussion, but if you have some fresh ideas on what this should look like (e.g. how to maintain type safety and/or offer a clean DSL), please do weigh in! There's also a Gitter channel if you prefer the more personal touch.

Lastly, I'm curious about the "path" generation/transformation properties mentioned by @kolloch; Accord automatically generates a string description for each "thing" being validated. A "thing" could be property access, modifier (.each or .size) or an arbitrary expression, and in all cases Accord does its best to figure out a good representation of the inspected property. This can be overridden per-rule using as, but the description generation mechanism is not yet pluggable, is fairly naïve, and could use a lot of improvement. Our own services don't normally externalize validation errors, and so again I would dearly appreciate input on how this could be modelled.

Thank you for trying out Accord, I hope you've been enjoying it so far!

@nnordrum
Copy link

nnordrum commented Mar 4, 2016

This also appears to have broken relative paths in dependencies, or at least changed how they are represented.

"dependencies":["../hub"]

I have this in my deployment of a selenium grid, and this worked before 0.15.3, but doesn't now.

How do you represent this relatively now? All the examples and tests seem to be full path, which I would rather not do for what I think would think would be relatively obvious reasons.

@marcomonaco marcomonaco added the pr label Mar 6, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants