Creating ruleset for API Governance - Anypoint Platform - mule

/example:
/{uriParams}:
get:
is: [defaultResponses, commonHeaders]
uriParameters:
uriParams:
description: Example description uriParams
body:
application/json:
example: !include examples.example.json
I would like creating the ruleset that checking the example !include and the traits (defaultResponse, commonHeaders) Now I have like this but this ruleset working separately.(It's mean that if I have ruleset with "traits" and "example" in the same file there is only working "traits". If I delete the ruleset from file "traits". It's working the ruleset "example".) But I would like that they working together.
And also I'm trying doing ruleset for checking all fields are have name with camelCase example: "camelCase-exampleTwo"
provide-examples:
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)
traits:
message: common default
targetClass: apiContract.EndPoint
propertyConstraints:
apiContract.ParametrizedTrait:
core.name:
pattern: defaultResponses
camel-case-fields:
message: Use camelCase.
targetClass: apiContract.EndPoint
if:
propertyConstraints:
shacl.name:
in: ['path']
then:
propertyConstraints:
shacl.name:
pattern: "^[a-z]+([A-Z][a-z]+)*$"

Related

Karate: Unable to move schema definition out of feature file

I'm able to successfully run the Feature/scenario, When I define the schema inside my feature file .
Here is a simplified example of the schema.
Background:
...
...
* def accountSchema = { id: '#number? _ >= 0', prop1: '#number? _ >= 0', prop2: '#string', prop3: '#string', optionaProp: '##string' }
* def userAccountsSchema = ({ entitledAccounts: '#[] accountSchema', prop5: '#number' , prop6: '##string'})
And here is how I'm validating
Scenario:
...
...
When method GET
Then status 200
* print userAccountsSchema
And match response == userAccountsSchema
But the schema I posted here is simplified to ask this question, the real schema is far more complex.
So for clarity purpose, I decided to put schema in a separate js file response-schemas.js under the same folder as the feature file.
Here is the simplified content of response-schemas.js file.
function schema () {
let accountSchema = {
id: '#number? _ >= 0',
prop1: '#number? _ >= 0',
prop2: '#string',
prop3: '#string',
optionaProp: '##string',
}'
return {
accounts: `#[] ${accountSchema}` ,
prop5: '#string',
prop6: '#string',
};
}
now if I replace the 2 lines I mentioned at the beginning of the question under Background:, with below line
* def userAccountsSchema = call read('response-schemas.js')
I get this error
And match response == schemas
SyntaxError: Unnamed:1:8 Expected comma but found ident
[object Object]
^
I believe, I understand the problem, is this line
accounts: `#[] ${accountSchema}` ,
but unable to figure out the solution. If I tried to change the accountSchema variable in response-schemas.js to use multiline string then I get error in read step in Background
the whole idea to have a dedicated js file for schema is to keep it readable (by using multiple lines, preferably objects not a long string)
The main problem is this part:
accounts: `#[] ${accountSchema}`
Where you are trying to stuff a JSON into the Karate "fuzzy" expression. This is just not supported. Note that the Karate way of defining things like #(foo) and #[] bar has nothing to do with JavaScript, so I recommend not mixing these.
I know there is a desire to achieve the match in just one-line and somehow get one monstrous schema to do everything and I very strongly discourage this. Split your assertions into multiple lines. Split your response into smaller chunks of JSON if needed. There is nothing wrong with that. This also makes the life much easier of people who come along later who have to maintain your test.
For ideas see this answer: https://stackoverflow.com/a/61252709/143475
Other answers: https://stackoverflow.com/search?q=%5Bkarate%5D+array+schema
Tip: you can keep your schema "chunks" as JSON files if needed.

Karate : dynamic test data using scenario outline is not working in some cases

I was tryiny to solve dynamic test data problem using dynamic scenario outline as mentioned in the documentation https://github.com/karatelabs/karate#dynamic-scenario-outline
It worked perfectly fine when I passed something like this in Example section
Examples:
|[{'entity':country},{'entity':state},{'entity':district},{'entity':corporation}]]
But I tried to generate this json object programatically , I am getting aa strange error
WARN com.intuit.karate - ignoring dynamic expression, did not evaluate to list: users - [type: MAP, value: com.intuit.karate.ScriptObjectMap#2b8bb184]
Code to generate json object
* def user =
"""
function(response){
entity_type_ids =[]
var entityTypes = response.entityTypes
for(var i =0;i<entityTypes.length;i++ ){
object = {}
object['entity'] = entityTypes[i].id
entity_type_ids.push(object)
}
return JSON.stringify(entity_type_ids)
}
"""

I am trying to get data over an OpenWeather API in Rust but I am facing some iusse regarding parsing I guess

extern crate openweather;
use openweather::LocationSpecifier;
static API_KEY: &str = "e85e0a3142231dab28a2611888e48f22";
fn main() {
let loc = LocationSpecifier::Coordinates {
lat: 24.87,
lon: 67.03,
};
let weather = openweather::get_current_weather(loc, API_KEY).unwrap();
print!(
"Right now in Minneapolis, MN it is {}K",
weather.main.humidity
);
}
error : thread 'main' panicked at 'called Result::unwrap() on an
Err value: ErrorReport { cod: 0, message: "Got unexpected response:
\"{\\"coord\\":{\\"lon\\":67.03,\\"lat\\":24.87},\\"weather\\":[{\\"id\\":803,\\"main\\":\\"Clouds\\",\\"description\\":\\"broken
clouds\\",\\"icon\\":\\"04n\\"}],\\"base\\":\\"stations\\",\\"main\\":{\\"temp\\":294.15,\\"pressure\\":1018,\\"humidity\\":60,\\"temp_min\\":294.15,\\"temp_max\\":294.15},\\"visibility\\":6000,\\"wind\\":{\\"speed\\":5.1,\\"deg\\":30},\\"clouds\\":{\\"all\\":70},\\"dt\\":1574012543,\\"sys\\":{\\"type\\":1,\\"id\\":7576,\\"country\\":\\"PK\\",\\"sunrise\\":1573955364,\\"sunset\\":1573994659},\\"timezone\\":18000,\\"id\\":1174872,\\"name\\":\\"Karachi\\",\\"cod\\":200}\""
}
The issue is a JSON parsing error due to the deserialized struct not matching OpenWeather's JSON, perhaps the API recently added this? With your example, the OpenWeatherCurrent struct is missing timezone.
But it looks like there is an open PR that will fix this, you can test it by doing the following:
Change your Cargo.toml dependency to openweather = { git = "https://github.com/caemor/openweather" }.
The PR author has also updated the get_current_weather signature so you'll need to change lines 2, 10 to the following:
use openweather::{LocationSpecifier, Settings};
let weather = openweather::get_current_weather(&loc, API_KEY, &Settings::default()).unwrap();

Karate doesn't recognize dashes

I wrote a simple mock that checks if a specific header exists then return a specif response based on that, but karate doesn't understand dashes(-) in my headers for an example Client-ID gives an error of ReferenceError: "ID" is not defined in <eval> at line number 1 but header Accept work fine. i'm passing this header through postman.
and this how the code looks
* def fun = function(){ var test = requestHeaders; for(i in test) if(test.Client-ID) return true}
When you have characters like - part of the JSON key, you need to use quotes.
* def foo = { 'Content-Type': 'application/json' }
* match foo['Content-Type'] == 'application/json'
Also try if this works for you, it may be simpler:
Scenario: pathMatches('/v1/headers') && karate.get("requestHeaders['Client-ID']")
And in case you are testing a value, headerContains() can be used: https://github.com/intuit/karate/tree/master/karate-netty#headercontains

Karate API Testing - verify if "retriever" breed is within the list

I am testing a public API that lists all types of breeds.
'https://dog.ceo/api/breeds/list/all'
Within the response I need to verify if "retriever" breed is within the list. My feature file looks like this
Feature: Testing a REST API
Scenario: Testing valid GET endpoint
Given url 'https://dog.ceo/api/breeds/list/all'
When method GET
Then status 200
And print response
And match response.message contains 'retriever'
However I get the following error:
com.intuit.karate.exception.KarateException: path: $.message, actual:
{affenpinscher=[], african=[], airedale=[], akita=[], appenzeller=[],
basenji=[], beagle=[], bluetick=[], borzoi=[], bouvier=[], boxer=[],
brabancon=[], briard=[], bulldog=["boston","french"],
bullterrier=["staffordshire"], cairn=[], cattledog=["australian"],
chihuahua=[], chow=[], clumber=[], cockapoo=[], collie=["border"],
coonhound=[], corgi=["cardigan"], cotondetulear=[], dachshund=[],
dalmatian=[], dane=["great"], deerhound=["scottish"], dhole=[],
dingo=[], doberman=[], elkhound=["norwegian"], entlebucher=[],
eskimo=[], frise=["bichon"], germanshepherd=[], greyhound=["italian"],
groenendael=[],
hound=["afghan","basset","blood","english","ibizan","walker"],
husky=[], keeshond=[], kelpie=[], komondor=[], kuvasz=[], labrador=[],
leonberg=[], lhasa=[], malamute=[], malinois=[], maltese=[],
mastiff=["bull","tibetan"], mexicanhairless=[], mix=[],
mountain=["bernese","swiss"], newfoundland=[], otterhound=[],
papillon=[], pekinese=[], pembroke=[], pinscher=["miniature"],
pointer=["german","germanlonghair"], pomeranian=[],
poodle=["miniature","standard","toy"], pug=[], puggle=[], pyrenees=[],
redbone=[], retriever=["chesapeake","curly","flatcoated","golden"],
ridgeback=["rhodesian"], rottweiler=[], saluki=[], samoyed=[],
schipperke=[], schnauzer=["giant","miniature"],
setter=["english","gordon","irish"], sheepdog=["english","shetland"],
shiba=[], shihtzu=[],
spaniel=["blenheim","brittany","cocker","irish","japanese","sussex","welsh"], springer=["english"], stbernard=[],
terrier=["american","australian","bedlington","border","dandie","fox","irish","kerryblue","lakeland","norfolk","norwich","patterdale","russell","scottish","sealyham","silky","tibetan","toy","westhighland","wheaten","yorkshire"],
vizsla=[], weimaraner=[], whippet=[], wolfhound=["irish"]}, expected:
'retriever', reason: actual value is not a string
Look at the response structure carefully. These will work:
And match response.message contains { retriever: '#array' }
And match response.message.retriever == ['chesapeake', 'curly', 'flatcoated', 'golden']
Do read the documentation and examples.