HTTP RESPONSES
Response Data
Overview
The response
variable is automatically set after every HTTP call and contains the response body. Karate intelligently handles different content types, making it easy to work with JSON, XML, text, and binary responses.
Accessing Response Data
The Response Variable
# Response is automatically available after HTTP call
* url apiUrl
* path '/users/123'
* method get
* status 200
* print 'Response:', response
# Response type depends on Content-Type header
# JSON response -> JavaScript object
# XML response -> XML document object
# Text response -> String
# Binary response -> byte array
```gherkin
### Response as JSON
```gherkin
# JSON responses are automatically parsed
* url apiUrl
* path '/api/user'
* method get
* status 200
# Direct property access
* def userName = response.name
* def userAge = response.age
* def city = response.address.city
# Array access
* def firstItem = response.items[0]
* def lastItem = response.items[response.items.length - 1]
```gherkin
### Response as XML
```gherkin
# XML responses are automatically parsed
* url apiUrl
* path '/api/user.xml'
* method get
* status 200
# XPath access
* def name = response/user/name
* def email = response/user/email
# Alternative JSON-like access
* def name = response.user.name
* def attributes = response.user['@attributes']
```gherkin
## Response Data Extraction
### Saving Response Parts
```gherkin
# Save entire response
* def savedResponse = response
# Save specific fields
* def userId = response.id
* def userProfile = response.profile
* def permissions = response.user.permissions
# Save with default values
* def status = response.status || 'unknown'
* def items = response.items || []
```gherkin
### JsonPath Extraction
```gherkin
# Using $ as response shorthand
* def names = $.users[*].name
* def activeUsers = $.users[?(@.active == true)]
* def firstEmail = $.users[0].email
# Using get with JsonPath
* def allPrices = get response.products[*].price
* def expensiveItems = get response $.items[?(@.price > 100)]
```gherkin
### Deep Property Access
```gherkin
# Safe deep access
* def city = response.user.address.city
* def zipCode = karate.get('response.user.address.zip', '00000')
# Dynamic property access
* def fieldName = 'email'
* def value = response.user[fieldName]
# Nested array access
* def item = response.orders[0].items[2].product.name
```gherkin
## Response Type Handling
### JSON Responses
```gherkin
Scenario: Handle JSON response
* url apiUrl
* path '/api/data.json'
* method get
* status 200
# Verify it's JSON
* match responseType == 'json'
# Work with JSON data
* match response == { id: '#number', name: '#string' }
* def id = response.id
* def items = response.items || []
```gherkin
### XML Responses
```gherkin
Scenario: Handle XML response
* url apiUrl
* path '/api/data.xml'
* method get
* status 200
# Verify it's XML
* match responseType == 'xml'
# Work with XML data
* match response/root/item == 'value'
* def xmlString = karate.prettyXml(response)
```gherkin
### Text Responses
```gherkin
Scenario: Handle text response
* url apiUrl
* path '/api/message'
* header Accept = 'text/plain'
* method get
* status 200
# Work with text
* match responseType == 'string'
* match response contains 'success'
* def lines = response.split('\n')
```gherkin
### Binary Responses
```gherkin
Scenario: Handle binary response
* url apiUrl
* path '/api/download/file.pdf'
* method get
* status 200
# Access as bytes
* def bytes = responseBytes
* assert bytes.length > 0
# Save to file
* karate.write(bytes, 'target/download.pdf')
```gherkin
## Response Data Validation
### Basic Validation
```gherkin
# Check response exists
* assert response != null
* assert response.length > 0
# Type checking
* match response == '#object'
* match response.items == '#array'
* match response.count == '#number'
* match response.active == '#boolean'
```gherkin
### Complex Validation
```gherkin
# Validate structure
* match response ==
"""
{
id: '#number',
name: '#string',
email: '#regex .+@.+',
profile: {
age: '#? _ >= 18',
interests: '#array'
},
metadata: '#object'
}
"""
# Partial matching
* match response contains { status: 'active' }
* match response.items contains { id: 123 }
```gherkin
### Array Response Validation
```gherkin
# Array of objects
* match response == '#array'
* match response[0] == { id: '#number', name: '#string' }
* match each response == { id: '#number', name: '#string' }
# Array operations
* def count = response.length
* def firstItem = response[0]
* def lastItem = response[response.length - 1]
* def filtered = response.filter(x => x.active)
```gherkin
## Response Data Transformation
### Data Mapping
```gherkin
# Transform response data
* def usernames = response.users.map(x => x.username)
* def activeCount = response.items.filter(x => x.active).length
# Create new structure
* def summary = {
total: response.count,
items: response.data,
hasMore: response.next != null
}
```gherkin
### Data Aggregation
```gherkin
# Calculate from response
* def total = response.items.reduce((sum, item) => sum + item.price, 0)
* def average = total / response.items.length
# Group by property
* def grouped = {}
* eval response.items.forEach(item => {
if (!grouped[item.category]) grouped[item.category] = [];
grouped[item.category].push(item);
})
```gherkin
### Response Flattening
```gherkin
# Flatten nested structure
* def flattenUser = function(user) {
return {
id: user.id,
name: user.name,
email: user.contact.email,
city: user.address.city,
country: user.address.country
}
}
* def flatUsers = response.users.map(flattenUser)
```gherkin
## Conditional Response Handling
### Response-Based Logic
```gherkin
# Different handling based on response
* if (response.status == 'pending') karate.call('wait-for-completion.feature')
* if (response.requiresAuth) karate.call('authenticate.feature')
* if (response.items.length == 0) karate.fail('No items returned')
# Default values
* def data = response.data || []
* def message = response.message || 'No message'
```gherkin
### Error Response Handling
```gherkin
# Check for error in response
* if (response.error) karate.fail('API error: ' + response.error.message)
# Handle different error structures
* def error = response.error || response.errors || response.message
* if (error) karate.log('Error detected:', error)
# Validate error response
* if (responseStatus != 200) match response == {
error: '#string',
code: '#string',
details: '#array'
}
```gherkin
## Response Caching and Storage
### Storing Response Data
```gherkin
# Store for later use
Background:
* def userData = {}
Scenario: Cache response
* url apiUrl
* path '/user/profile'
* method get
* status 200
* set userData.profile = response
# Use cached data
* print 'Cached profile:', userData.profile
```gherkin
### Response Comparison
```gherkin
# Compare responses
* def firstResponse = response
* url apiUrl
* path '/api/endpoint'
* method get
* def secondResponse = response
# Check if responses match
* match firstResponse == secondResponse
# Check specific differences
* match firstResponse.id != secondResponse.id
* match firstResponse.timestamp != secondResponse.timestamp
```gherkin
## Advanced Response Patterns
### Paginated Responses
```gherkin
# Handle pagination
* def allItems = []
* def page = 1
* def hasMore = true
* eval
"""
while (hasMore) {
karate.set('url', apiUrl);
karate.set('path', '/items');
karate.set('param', { page: page, size: 100 });
karate.call('get-request.feature');
allItems = allItems.concat(karate.get('response.items'));
hasMore = karate.get('response.hasNext');
page++;
}
"""
```gherkin
### Streaming Responses
```gherkin
# Handle server-sent events
* url eventStreamUrl
* path '/events'
* header Accept = 'text/event-stream'
* method get
# Process stream data
* def events = response.split('\n\n')
* def parsedEvents = events.map(e => JSON.parse(e.replace('data: ', '')))
```gherkin
### Response Polling
```gherkin
# Poll until response changes
* def waitForStatus = function(expectedStatus) {
var maxAttempts = 10;
for (var i = 0; i < maxAttempts; i++) {
karate.call('check-status.feature');
if (karate.get('response.status') === expectedStatus) {
return true;
}
java.lang.Thread.sleep(2000);
}
return false;
}
* assert waitForStatus('completed') == true
```gherkin
## Best Practices
### Response Validation
```gherkin
# ✅ Good: Validate response structure
* match response == { id: '#number', data: '#array' }
* assert response.items.length > 0
# ❌ Avoid: Assuming response structure
* def id = response.user.profile.id # Could fail if structure changes
```gherkin
### Error Handling
```gherkin
# ✅ Good: Safe access with defaults
* def items = response.items || []
* def count = response.count || 0
# ✅ Good: Check before access
* if (response && response.data) def result = response.data
```gherkin
### Response Documentation
```gherkin
# ✅ Good: Document expected response
Scenario: Get user details
"""
Expected response:
{
id: number,
name: string,
email: string,
profile: {
age: number,
interests: string[]
}
}
"""
* url apiUrl
* path '/user/', userId
* method get
* status 200
* match response == '#object'
```gherkin
## Next Steps
- Learn about [Headers and Cookies](/docs/http-responses/headers-cookies) for metadata
- Explore [Assertions](/docs/assertions/match-keyword) for validation
- Understand [Reusability](/docs/reusability/calling-features) for common patterns