Search code examples
karate

Validate response against a list of expected and not-permitted headers in Karate


I have a problem where a customer wants a guarantee that certain HTTP headers are always returned in all API responses (i.e. required headers) and that certain headers are never returned in all API responses (i.e. restricted headers).

What I want to be able to do is have a list of required headers and a list of restricted headers, and then for every HTTP response, if a header is found that is in the restricted list, the test case fails, and similarly the test will also fail if a response is missing a header from the required list. This feels like it should be a pretty trivial problem to solve, but I am having hard figuring out how to make it work without having to copy and paste duplicate code into dozens of feature files.

Is there an idiomatic way to set this up globally in karate-config.js?

[Disclaimer: developer of Karate here adding a FAQ for the benefit of the user community]


Solution

  • Yes, it should be easy to create a common function that is set up in karate-config.js. Here is an example:

    function fn(config) {
        if (!config) {
            config = {};
        }
        if (!config.present) {
            config.present = [];
        }
        if (!config.notpresent) {
            config.notpresent = [];
        }
        var headers = karate.get('responseHeaders');
        var keys = Object.keys(headers).map(x => x.toLowerCase());
        // karate.log('header keys:', keys);
        config.present.forEach(present => {
            if (!keys.includes(present)) {
                karate.fail('expected header not present: ' + present);
            }
        });
        keys.forEach(key => {
            if (config.notpresent.includes(key)) {
                karate.fail('header present but not expected: ' + key);
            }
        });
    }
    

    Assume this file above is called header-check.js and side-by-side with karate-config.js. Now you can do this in karate-config.js:

    function fn() {
        return { headerCheck: read('classpath:header-check.js') }
    }
    

    Now your features just have to call headerCheck():

    * url 'https://httpbin.org/anything'
    * request {}
    * method post
    * status 200
    * headerCheck({ present: ['content-type'], notpresent: ['connection'] })
    

    I hope this gives you a starting point, you can have various strategies to dynamically set the list of headers or hard-code them. Note how you can fail a Karate test with a friendly error message via the karate.fail() API.

    I think having to call headerCheck() after every call is reasonable. If you really wanted this abstracted away, the only way to do it is use a Java hook, and the RuntimeHook has an afterHttpCall() call-back.