HTTP RESPONSES
Headers and Cookies
Overview
Response headers and cookies provide crucial metadata about HTTP responses. Karate offers powerful tools for accessing, validating, and utilizing this information in your test flows.
Response Headers
Accessing Headers
# Response headers are available as a map of lists
* def contentType = responseHeaders['Content-Type'][0]
* def cacheControl = responseHeaders['Cache-Control'][0]
* def customHeader = responseHeaders['X-Custom-Header'][0]
# Case-insensitive access (with configuration)
* configure lowerCaseResponseHeaders = true
* def contentType = responseHeaders['content-type'][0]
# Check header existence
* assert responseHeaders['X-Rate-Limit']
* assert !responseHeaders['X-Debug-Info']
```gherkin
### Header Validation
```gherkin
# Match specific header
* match header Content-Type == 'application/json'
* match header X-API-Version == '2.0'
# Header with regex
* match header Location == '#regex https://.+/users/\\d+'
# Multiple header validation
* match responseHeaders contains {
'Content-Type': ['application/json'],
'X-API-Version': ['#string']
}
# Partial header matching
* match responseHeaders contains deep {
'Cache-Control': ['#regex .*max-age=\\d+.*']
}
```gherkin
### Common Headers
```gherkin
Scenario: Validate common response headers
* url apiUrl
* path '/api/data'
* method get
* status 200
# Content headers
* match header Content-Type contains 'application/json'
* match header Content-Length == '#string'
* match header Content-Encoding == 'gzip'
# Cache headers
* match header Cache-Control contains 'max-age'
* match header ETag == '#string'
* match header Last-Modified == '#string'
# CORS headers
* match header Access-Control-Allow-Origin == '*'
* match header Access-Control-Allow-Methods contains 'GET'
```gherkin
## Response Cookies
### Accessing Cookies
```gherkin
# Response cookies are available as a map
* def sessionCookie = responseCookies.sessionId
* def authCookie = responseCookies.authToken
# Cookie properties
* def cookieValue = sessionCookie.value
* def cookieDomain = sessionCookie.domain
* def cookiePath = sessionCookie.path
* def cookieExpiry = sessionCookie['max-age']
* def isSecure = sessionCookie.secure
* def isHttpOnly = sessionCookie.httpOnly
```gherkin
### Cookie Validation
```gherkin
# Validate cookie existence
* match responseCookies contains { sessionId: '#object' }
# Validate cookie properties
* match responseCookies.sessionId == {
value: '#string',
domain: '.example.com',
path: '/',
secure: true,
httpOnly: true,
'max-age': '#number'
}
# Check multiple cookies
* match responseCookies contains {
sessionId: '#object',
preferences: '#object'
}
```gherkin
### Cookie Management
```gherkin
Scenario: Cookie handling flow
# Login and receive cookies
* url authUrl
* path '/login'
* request { username: 'user', password: 'pass' }
* method post
* status 200
# Extract cookies
* def session = responseCookies.sessionId.value
* def auth = responseCookies.authToken.value
# Use cookies in next request
* url apiUrl
* path '/protected'
* cookie sessionId = session
* cookie authToken = auth
* method get
* status 200
# Validate cookie updates
* match responseCookies.sessionId.value == session
* match responseCookies.lastActivity != null
```gherkin
## Response Metadata
### Response Time
```gherkin
# Response time in milliseconds
* assert responseTime < 1000
* print 'API responded in', responseTime, 'ms'
# Performance thresholds
* def performanceThresholds = {
fast: 100,
acceptable: 500,
slow: 1000
}
* if (responseTime < performanceThresholds.fast) karate.log('Fast response')
* if (responseTime > performanceThresholds.slow) karate.log('Slow response:', responseTime)
# Track response times
* def responseTimes = []
* responseTimes.push(responseTime)
* def avgTime = responseTimes.reduce((a, b) => a + b) / responseTimes.length
```gherkin
### Response Type
```gherkin
# Check response content type
* assert responseType == 'json'
* assert responseType == 'xml'
* assert responseType == 'string'
* assert responseType == 'bytes'
# Type-specific handling
* if (responseType == 'json') def data = response
* if (responseType == 'xml') def data = response/root
* if (responseType == 'string') def lines = response.split('\n')
* if (responseType == 'bytes') def size = responseBytes.length
```gherkin
### Response Size
```gherkin
# Check response size
* def responseSize = responseBytes.length
* print 'Response size:', responseSize, 'bytes'
* assert responseSize < 1048576 # Less than 1MB
# Content-Length validation
* def contentLength = parseInt(responseHeaders['Content-Length'][0])
* match contentLength == responseSize
```gherkin
## Advanced Header Patterns
### Security Headers
```gherkin
Scenario: Validate security headers
* url apiUrl
* path '/api/secure'
* method get
* status 200
# Security headers validation
* match header X-Content-Type-Options == 'nosniff'
* match header X-Frame-Options == 'DENY'
* match header X-XSS-Protection == '1; mode=block'
* match header Strict-Transport-Security contains 'max-age='
* match header Content-Security-Policy == '#string'
# Check for absence of sensitive headers
* assert !responseHeaders['X-Powered-By']
* assert !responseHeaders['Server']
```gherkin
### Authentication Headers
```gherkin
# Validate auth response headers
* match header WWW-Authenticate contains 'Bearer'
* match header X-Auth-Token == '#string'
* match header X-Token-Expires-In == '#number'
# Extract auth information
* def authToken = responseHeaders['X-Auth-Token'][0]
* def expiresIn = parseInt(responseHeaders['X-Token-Expires-In'][0])
* def refreshToken = responseHeaders['X-Refresh-Token'][0]
```gherkin
### Rate Limiting Headers
```gherkin
# Check rate limit headers
* def rateLimit = parseInt(responseHeaders['X-RateLimit-Limit'][0])
* def remaining = parseInt(responseHeaders['X-RateLimit-Remaining'][0])
* def reset = parseInt(responseHeaders['X-RateLimit-Reset'][0])
* print 'Rate limit:', remaining, '/', rateLimit
* if (remaining < 10) karate.log('Warning: Low rate limit remaining')
# Wait if rate limited
* if (responseStatus == 429) {
def retryAfter = parseInt(responseHeaders['Retry-After'][0])
eval java.lang.Thread.sleep(retryAfter * 1000)
}
```gherkin
## Cookie-Based Authentication
### Session Management
```gherkin
Background:
# Get session cookie
* def getSession = callonce read('get-session.feature')
* def sessionCookie = getSession.sessionCookie
Scenario: Use session across requests
* url apiUrl
* path '/api/data'
* cookie SESSION_ID = sessionCookie
* method get
* status 200
# Check session renewal
* if (responseCookies.SESSION_ID) def sessionCookie = responseCookies.SESSION_ID.value
```gherkin
### Cookie Refresh
```gherkin
# Auto-refresh expired cookies
* def refreshCookies =
"""
function() {
var session = karate.get('responseCookies.session');
if (session && session['max-age'] < 60) {
karate.call('refresh-session.feature');
return karate.get('responseCookies.session.value');
}
return session ? session.value : null;
}
"""
* def currentSession = refreshCookies()
```gherkin
## Performance Monitoring
### Header-Based Metrics
```gherkin
# Track performance via headers
* def serverTime = responseHeaders['X-Server-Processing-Time'][0]
* def cacheStatus = responseHeaders['X-Cache'][0] # HIT or MISS
* def cdn = responseHeaders['X-Served-By'][0]
* def metrics = {
responseTime: responseTime,
serverTime: parseInt(serverTime),
cacheHit: cacheStatus == 'HIT',
cdn: cdn
}
* print 'Performance metrics:', metrics
```gherkin
### Cookie Tracking
```gherkin
# Track cookie changes
* def trackCookies = function(cookies) {
var tracked = {};
for (var name in cookies) {
tracked[name] = {
value: cookies[name].value,
expires: cookies[name]['max-age'],
secure: cookies[name].secure
};
}
return tracked;
}
* def cookieState = trackCookies(responseCookies)
* print 'Cookie state:', cookieState
```gherkin
## Debugging Headers and Cookies
### Header Inspection
```gherkin
# Debug all headers
* print 'Response headers:', responseHeaders
# Pretty print headers
* def printHeaders = function(headers) {
for (var name in headers) {
karate.log(name + ':', headers[name].join(', '));
}
}
* printHeaders(responseHeaders)
```gherkin
### Cookie Debugging
```gherkin
# Debug all cookies
* print 'Response cookies:', responseCookies
# Detailed cookie info
* def debugCookies = function(cookies) {
for (var name in cookies) {
var c = cookies[name];
karate.log('Cookie:', name);
karate.log(' Value:', c.value);
karate.log(' Domain:', c.domain);
karate.log(' Path:', c.path);
karate.log(' Secure:', c.secure);
karate.log(' HttpOnly:', c.httpOnly);
}
}
* debugCookies(responseCookies)
```gherkin
## Best Practices
### Header Validation
```gherkin
# ✅ Good: Validate critical headers
* match header Content-Type contains 'json'
* assert responseHeaders['X-Request-ID']
# ✅ Good: Use appropriate validation
* match header Cache-Control == '#regex .*max-age=\\d+.*'
```gherkin
### Cookie Security
```gherkin
# ✅ Good: Validate secure cookies
* assert responseCookies.auth.secure == true
* assert responseCookies.auth.httpOnly == true
# ✅ Good: Check cookie expiry
* assert responseCookies.session['max-age'] > 0
```gherkin
### Performance Tracking
```gherkin
# ✅ Good: Track key metrics
Background:
* def performanceLog = []
Scenario: Track performance
* url apiUrl
* method get
* performanceLog.push({
endpoint: '/api/data',
time: responseTime,
cached: responseHeaders['X-Cache'][0] == 'HIT'
})
```gherkin
## Next Steps
- Learn about [Assertions](/docs/assertions/match-keyword) for comprehensive validation
- Explore [Reusability](/docs/reusability/calling-features) for common patterns
- Understand [Advanced Features](/docs/advanced/configuration) for complex scenarios