github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/mw_validate_json.go (about)

     1  package gateway
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  
     9  	"github.com/TykTechnologies/gojsonschema"
    10  	"github.com/TykTechnologies/tyk/apidef"
    11  )
    12  
    13  type ValidateJSON struct {
    14  	BaseMiddleware
    15  }
    16  
    17  func (k *ValidateJSON) Name() string {
    18  	return "ValidateJSON"
    19  }
    20  
    21  func (k *ValidateJSON) EnabledForSpec() bool {
    22  	for _, v := range k.Spec.VersionData.Versions {
    23  		if len(v.ExtendedPaths.ValidateJSON) > 0 {
    24  			return true
    25  		}
    26  	}
    27  
    28  	return false
    29  }
    30  
    31  // ProcessRequest will run any checks on the request on the way through the system, return an error to have the chain fail
    32  func (k *ValidateJSON) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
    33  
    34  	_, versionPaths, _, _ := k.Spec.Version(r)
    35  	found, meta := k.Spec.CheckSpecMatchesStatus(r, versionPaths, ValidateJSONRequest)
    36  	if !found {
    37  		return nil, http.StatusOK
    38  	}
    39  
    40  	vPathMeta := meta.(*apidef.ValidatePathMeta)
    41  	if vPathMeta.Schema == nil {
    42  		return errors.New("no schemas to validate against"), http.StatusInternalServerError
    43  	}
    44  
    45  	if val, exists := vPathMeta.Schema["$schema"]; exists {
    46  		if val != "http://json-schema.org/draft-04/schema#" {
    47  			return errors.New("unsupported schema, unable to validate"), http.StatusInternalServerError
    48  		}
    49  	}
    50  
    51  	// Load input body into gojsonschema
    52  	bodyBytes, err := ioutil.ReadAll(r.Body)
    53  	if err != nil {
    54  		return err, http.StatusBadRequest
    55  	}
    56  	defer r.Body.Close()
    57  	inputLoader := gojsonschema.NewBytesLoader(bodyBytes)
    58  
    59  	// Perform validation
    60  	result, err := gojsonschema.Validate(vPathMeta.SchemaCache, inputLoader)
    61  	if err != nil {
    62  		return fmt.Errorf("JSON parsing error: %v", err), http.StatusBadRequest
    63  	}
    64  
    65  	// Handle Failure
    66  	if !result.Valid() {
    67  		if vPathMeta.ErrorResponseCode == 0 {
    68  			vPathMeta.ErrorResponseCode = http.StatusUnprocessableEntity
    69  		}
    70  
    71  		return k.formatError(result.Errors()), vPathMeta.ErrorResponseCode
    72  	}
    73  
    74  	// Handle Success
    75  	return nil, http.StatusOK
    76  }
    77  
    78  func (k *ValidateJSON) formatError(schemaErrors []gojsonschema.ResultError) error {
    79  	errStr := ""
    80  	for i, desc := range schemaErrors {
    81  		if i == 0 {
    82  			errStr = desc.String()
    83  		} else {
    84  			errStr = errStr + "; " + desc.String()
    85  		}
    86  	}
    87  
    88  	return errors.New(errStr)
    89  }