compare jsonSchema def with a Go struct def - fail at app layer not db layer

26 Views Asked by At

JsonSchema for mongodb purposes looks like this:

package main

import (
    "context"
    "log"
    "go.mongodb.org/mongo-driver/bson"
    "go.mongodb.org/mongo-driver/mongo"
    "go.mongodb.org/mongo-driver/mongo/options"
)

func main() {

    jsonSchema := bson.M{
        "bsonType": "object",
        "required": []string{"name", "age"},
        "properties": bson.M{
            "name": bson.M{
                "bsonType":    "string",
                "minLength":   1, // Minimum length of 1 character
                "maxLength":   50, // Maximum length of 50 characters
                "description": "must be a string with 1 to 50 characters and is required",
            },
            "age": bson.M{
                "bsonType":    "int",
                "minimum":     0,
                "description": "must be an integer greater than or equal to 0 and is required",
            },
        },
    }

    validationOptions := options.CreateCollection().SetValidator(bson.M{"$jsonSchema": jsonSchema})

    err = db.CreateCollection(context.TODO(), "your_collection_name", validationOptions)
    
    collection := db.Collection("your_collection_name")

    newPerson := Person{Name: "John Doe", Age: 30}   // NUM #1
    insertResult, err := collection.InsertOne(context.Background(), newPerson)
    
    // or we could do this instead:

    newPerson := bson.D{{"name", "John Doe"}, {"age", 30}}  // NUM #2
    insertResult, err := collection.InsertOne(context.Background(), newPerson)

    
}

my question is - is there a library/technique that can validate the person struct (#1) or the bson.M person map (#2) against the jsonSchema map definition before inserting to that db? That way we can fail early at the application level and know that the struct/bson.M declaration match the schema. (And also test it at app layer).

1

There are 1 best solutions below

0
Alexander Mills On

This seems to work, but if someone knows of a better way, please let me know:

import (
    "encoding/json"
    "github.com/xeipuuv/gojsonschema"
)

func validateAgainstSchema(doc bson.M, jsonSchema string) error {

    jsonDoc, err := json.Marshal(doc)
    if err != nil {
        return err
    }

    documentLoader := gojsonschema.NewStringLoader(string(jsonDoc))
    schemaLoader := gojsonschema.NewStringLoader(jsonSchema)

    result, err := gojsonschema.Validate(schemaLoader, documentLoader)
    if err != nil {
        return err
    }

    if !result.Valid() {
        return errors.New(result.String())
    }

    return nil
}


bsonDoc := bson.M{"name": "John", "age": 30}
err := validateAgainstSchema(bsonDoc, yourJSONSchemaString)
if err != nil {
    // Handle validation error
}