Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSON Schema Validator #111

Open
snadrus opened this issue Sep 14, 2020 · 5 comments
Open

JSON Schema Validator #111

snadrus opened this issue Sep 14, 2020 · 5 comments
Labels
feature request Request for new feature implementation

Comments

@snadrus
Copy link

snadrus commented Sep 14, 2020

Other than your input validator, consider the JSON Schema validator (jsonschema.org). Although similar, it has the advantage of write-once, run anywhere. The same validation schema could run on the browser before bothering the server. There would be no challenge keeping the two in synchronization: just use the same validator file.

@System-Glitch System-Glitch added the feature request Request for new feature implementation label Sep 14, 2020
@System-Glitch
Copy link
Member

System-Glitch commented Sep 14, 2020

Hello, can you write a more in-depth description of how you pictured it would work? How would it be used, with examples, etc. Would it be a middleware? Would it be something detached from the current validation system or an extension of it?

@snadrus
Copy link
Author

snadrus commented Sep 14, 2020

Today (from example):

var (
    StoreRequest validation.RuleSet = validation.RuleSet{
        "name":  {"required", "string", "between:3,50"},
        "price": {"required", "numeric", "min:0.01"},
        "image": {"nullable", "file", "image", "max:2048", "count:1"},
    }

    // ...
)
func Routes(router *goyave.Router) {
   router.Post("/product", product.Store).Validate(product.StoreRequest)
}

With a schema validator:

var (
    StoreRequest = ` 
{
 "$id": "https://example.com/productPost.schema.json", 
 "$schema": "http://json-schema.org/draft-07/schema#",
 "title": "ProductPost", 
 "type": "object", 
 "required": [ "name", "price" ],
 "properties": {
   "name": {
      "type": "string", 
      "minimum": 3, 
      "maximum": 50
   },
   "price": {
      "type": "number",
      "minimum": 0.01
   },
   "image": {
      "type": "string", 
      "maximum": 2048,
   }
 }
}`
)
func Routes(router *goyave.Router) {
    // Uses the Go JSON schema validator:
   router.Post("/product", product.Store).ValidateWithJSONSchema(StoreRequest)

   // So the browser can run the Javascript version of the JSON schema validator too:
   router.Get("/productPost.schema.json", func(response *goyave.Response, request *goyave.Request){
      response.String(http.StatusOK, StoreRequest)
   })
}

The validators immediately tell the user what went wrong in the browser before the form posts to the user. It saves the user from waiting for a POST to process before finding out there's an error. The dev work is similar since the validators produce an error message like "name too long, max 50". To use, a Front-End dev only needs to:

  • get this schema,
  • Include <script> the validator, and
  • Use the Form's onSubmit hook to cancel POST if there's an error string returned from the validator. Ex:
function showErr(msg) {
   document.getElementByID('message').innerText = msg;
   return (msg=='');    // submit if no error to show
}
<form onSubmit="showErr( jsonSchema.Valid( await fetch('/productPost.schema.json'), $(this).serialize() ) )">

@System-Glitch System-Glitch added the good first issue Good for newcomers label Sep 30, 2020
@System-Glitch
Copy link
Member

System-Glitch commented Sep 30, 2020

@snadrus Sorry for the late response.

This has a caveat: the validator converts data into the type you are expecting to receive. For example, validating a URL converts the request data (a string) to a *url.URL. How would that work with a JSON schema validation? Validation would not guarantee data types anymore, unless you can think of a solution to remedy this?

It looks like you are trying to ease the work of the front-end developer while having to avoid duplicating validation settings. Maybe we could work on a module able to convert RuleSet into a JSON schema? (for example: RuleSet.ToJSONSchema())

@snadrus
Copy link
Author

snadrus commented Sep 30, 2020 via email

@System-Glitch
Copy link
Member

System-Glitch commented Oct 1, 2020

The problem with this is that we would have two way to validate incoming requests. One would not convert automatically so you would have to do it in the controller handler, the other does and you can retrieve it easily with the request object accessor.

Here is my suggestion:

On the backend, keep the same validation mechanism with RuleSet. But add a method to it to convert it easily to JSON Schema (RuleSet.ToJSONSchema()). This method would be used inside the handler for the route serving the JSON schema. (A router method could also be implemented to make this easier: router.JSONSchema(product.InsertRequest).
This way, there is no duplicate validation settings, data conversion is still effective, front-end is guaranteed to be validated exactly the same way as the backend, and without any performance hit. Implementation would be simpler and there would be less feature fragmentation.

Would that work for you?

@System-Glitch System-Glitch removed the good first issue Good for newcomers label May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request Request for new feature implementation
Projects
None yet
Development

No branches or pull requests

2 participants