How to validate JSON input using Golang?
Asked Answered
B

5

11

I'm using Beego framework to build a web application in Go. I have to validate the incoming JSON in an API request.

I can unmarshal the JSON into a struct which works fine, but I want to validate the data as well. For example, if the type doesn't match with the type in struct json.Unmarshal will reutrn an error on the first occurence. I want to validate and get all the errors at once for JSON.

I've tried https://github.com/thedevsaddam/govalidator but the package needs a reference to request object which is not available in the controller of Beego. There are other validators which can validate a struct but i want the json validation as well.

EDIT:

A reference to the request object in beego can be found from the controller's context object as:

func (this *MainController) Post() {
    fmt.Println(this.Ctx.Request)
}

But the problem remains same with json unmarshal. If there's any slight mismatch in the type, json.unmarshal will immediately panic. I want to be able to validate the type as well.

Bouton answered 30/5, 2019 at 12:26 Comment(3)
This isn't supported by the standard library, so it seems you're asking for a 3rd party lib? That is off-topic for SO.Sheya
Either a 3rd party library or any solution is welcomed.Bouton
json.Decoder.Token() might help, but it will require quite a bit of code.Balanced
S
13

Since Golang v1.9 json.Valid([]byte) has been a valid method available from the "encoding/json" package.

Reference: https://golang.org/pkg/encoding/json/#Valid

Syllabic answered 19/11, 2020 at 17:54 Comment(0)
U
6

We've used go-playground/validator.v8 for a similar purpose. You can define the data validations with the tags that come out of the box (basic stuff like equality, min/max and even has somthing of an expression lang). On top of that you can add your custom validations. It's all in the docs, hope it helps.

Undershrub answered 30/5, 2019 at 12:49 Comment(0)
R
1

There is a method checkValid (in encoding/json package) which can do that. This method, however, is not exposed. So, you can use Unmarshal (in same package) to check if JSON is valid.

Remy answered 18/9, 2019 at 11:17 Comment(0)
F
1

I had to do this today so I will share my solution. I created a function using unmarshal that returns true or false based on whether the text returns valid json:

// isJSON checks that the string value of the field can unmarshall into valid json
func isJSON(s string) bool {
    var j map[string]interface{}
    if err := json.Unmarshal([]byte(s), &j); err != nil {
        return false
    }
    return true
}

Then I used that logic with the validator package to make and register a custom validation tag that I can use in any struct to validate that a field contains json. You can use go playground to check the full solution and experiment:

// isJSON checks that the string value of the field can unmarshall into valid json
func isJSON(fl validator.FieldLevel) bool {
    var j map[string]interface{}
    if err := json.Unmarshal([]byte(fl.Field().String()), &j); err != nil {
        return false
    }
    return true
}

// register the function with json tag:
validate.RegisterValidation("json", isJSON)
Fatal answered 19/5, 2020 at 21:40 Comment(1)
Thanks this helped. I've updated isJson to return error: ``` func isJSON(s string) error { var j map[string]interface{} return json.Unmarshal([]byte(s), &j) } ```Neelyneeoma
S
0

For Django like forms, you can use this package. It's super small but supports all the basic stuff (required, min/max, choices, inner struct validation, etc...). On top of that, it's also simple to use.

You just have to define a struct with the values that you allow:

type Object struct {
    ID             *string    `validations:"type=string;required=true`
    Code           *int       `validations:"type=int;choices=1,2,3`
    Person         *Person    `validations:"type=struct`
    Owners         []string   `validations:"type=[]string`
    PersonList     []Person   `validations:"type=[]struct`
}

and then you just have to:

form := new(Object)
validationErrors := jsonValidator.Validate(c.Body(), form)

And the form will be populated!

Selfcontradiction answered 24/5 at 17:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.