Search code examples
mulesoftramlanypoint-platformapi-governance

Creating ruleset for API Governance


I'm trying creaiting ruleset for RAML to check if there are the example for responses and description for uriParams.

/example:    
      /{uriParams}:
        get:
          uriParameters:
          uriParams:
          description: Example description uriParams
          body:
          application/json:
          example: !include examples.example.json

And for this I create two ruleset but it's not working:

    response-example:
    message: Provide example.
    targetClass: apiContract.Example
    and:
       - propertyConstraints:
          apiContract.returns:
            atLeast:
                count: 1
                validation:
                 propertyConstraints:
                    apiContract.structuredValue:
                        pattern: "^!include"

  uri-descriptions:
    message: Provide descriptions.
    targetClass: apiContract.Parameter
    if:
      propertyConstraints:
        apiContract.Parameter:
          pattern: uri
    then:
      propertyConstraints:
        core.description:
          minCount: 1

Solution

  • Checking examples is non-trivial. AMF (RAML parser used for Governance) resolves them to the schema of the parameter, payload, header, etc. Just clarifying with an example: imagine that if you have a response of type Person and an example there, the example will be transferred from the response to the Person type.

    Fortunately AMF keeps an annotation called tracked-element that points back to the original parameter, payload, header, etc. where the example was defined. Unfortunately checking that these are the same element must be done with custom Rego code.

    Here's the resulting ruleset:

    
    profile: My Ruleset
    
    description: Example ruleset
    
    violation:
      - provide-examples-on-payloads
      - provide-description-on-parameters
    
    validations:
      provide-examples-on-payloads:
        message: Always include examples in request and response bodies
        targetClass: apiContract.Payload
        rego: |
          schema = find with data.link as $node["http://a.ml/vocabularies/shapes#schema"]
    
          nested_nodes[examples] with data.nodes as object.get(schema, "http://a.ml/vocabularies/apiContract#examples", [])
    
          examples_from_this_payload = { element |
            example = examples[_]
            sourcemap = find with data.link as object.get(example, "http://a.ml/vocabularies/document-source-maps#sources", [])
            tracked_element = find with data.link as object.get(sourcemap, "http://a.ml/vocabularies/document-source-maps#tracked-element", [])
            tracked_element["http://a.ml/vocabularies/document-source-maps#value"] = $node["@id"]
            element := example
          }
    
          $result := (count(examples_from_this_payload) > 0)
    
      provide-description-on-parameters:
        message: Always include examples in URI parameters
        targetClass: apiContract.Parameter
        if:
            propertyConstraints:
                apiContract.binding:
                    in: ['path']
        
        then:
            propertyConstraints:
                core.description:
                    minCount: 1