github.com/kaptinlin/jsonschema@v0.4.6/content.go (about)

     1  package jsonschema
     2  
     3  // EvaluateContent checks if the given data conforms to the encoding, media type, and content schema specified in the schema.
     4  // According to the JSON Schema Draft 2020-12:
     5  //   - The "contentEncoding" property defines how a string should be decoded from encoded binary data.
     6  //   - The "contentMediaType" describes the media type that the decoded data should conform to.
     7  //   - The "contentSchema" provides a schema to validate the structure of the decoded and unmarshalled data.
     8  //
     9  // This method ensures that the data instance conforms to the encoding, media type, and content schema constraints defined in the schema.
    10  // If any stage fails, it returns a EvaluationError detailing the specific failure.
    11  //
    12  // References:
    13  //   - https://json-schema.org/draft/2020-12/json-schema-validation#name-contentencoding
    14  //   - https://json-schema.org/draft/2020-12/json-schema-validation#name-contentmediatype
    15  //   - https://json-schema.org/draft/2020-12/json-schema-validation#name-contentschema
    16  func evaluateContent(schema *Schema, instance interface{}, _ map[string]bool, _ map[int]bool, dynamicScope *DynamicScope) (*EvaluationResult, *EvaluationError) {
    17  	value, isString := instance.(string)
    18  	if !isString {
    19  		return nil, nil // If instance is not a string, content validation is not applicable.
    20  	}
    21  
    22  	var content []byte
    23  	var parsedValue interface{}
    24  	var err error
    25  
    26  	// Decode the content if encoding is specified
    27  	if schema.ContentEncoding != nil {
    28  		decoder, exists := schema.compiler.Decoders[*schema.ContentEncoding]
    29  		if !exists {
    30  			return nil, NewEvaluationError("contentEncoding", "unsupported_encoding", "Encoding '{encoding}' is not supported", map[string]interface{}{
    31  				"encoding": *schema.ContentEncoding,
    32  			})
    33  		}
    34  		content, err = decoder(value)
    35  		if err != nil {
    36  			return nil, NewEvaluationError("contentEncoding", "invalid_encoding", "Error decoding data with '{encoding}'", map[string]interface{}{
    37  				"encoding": *schema.ContentEncoding,
    38  				"error":    err.Error(),
    39  			})
    40  		}
    41  	} else {
    42  		content = []byte(value) // Assume the content is the raw string if no encoding is specified
    43  	}
    44  
    45  	// Handle content media type validation
    46  	if schema.ContentMediaType != nil {
    47  		unmarshal, exists := schema.compiler.MediaTypes[*schema.ContentMediaType]
    48  		if !exists {
    49  			return nil, NewEvaluationError("contentMediaType", "unsupported_media_type", "Media type '{media_type}' is not supported", map[string]interface{}{
    50  				"media_type": *schema.ContentMediaType,
    51  			})
    52  		}
    53  		parsedValue, err = unmarshal(content)
    54  		if err != nil {
    55  			return nil, NewEvaluationError("contentMediaType", "invalid_media_type", "Error unmarshalling data with media type '{media_type}'", map[string]interface{}{
    56  				"media_type": *schema.ContentMediaType,
    57  				"error":      err.Error(),
    58  			})
    59  		}
    60  	} else {
    61  		parsedValue = content // If no media type is specified, pass the raw content
    62  	}
    63  
    64  	// Evaluate against the content schema if specified and value was decoded
    65  	if schema.ContentSchema != nil {
    66  		result, _, _ := schema.ContentSchema.evaluate(parsedValue, dynamicScope)
    67  		if result != nil {
    68  			//nolint:errcheck
    69  			result.SetEvaluationPath("/contentSchema").
    70  				SetSchemaLocation(schema.GetSchemaLocation("/contentSchema")).
    71  				SetInstanceLocation("")
    72  
    73  			if !result.IsValid() {
    74  				return result, NewEvaluationError("contentSchema", "content_schema_mismatch", "Content does not match the schema")
    75  			} else {
    76  				return result, nil
    77  			}
    78  		}
    79  	}
    80  
    81  	return nil, nil
    82  }