HTTP RESPONSES
Status Codes
Overview
HTTP status codes provide essential information about the outcome of API requests. Karate offers powerful tools for validating status codes and implementing conditional logic based on response outcomes.
Basic Status Validation
Simple Status Checks
# Exact status match
* status 200 # OK
* status 201 # Created
* status 204 # No Content
* status 404 # Not Found
* status 500 # Internal Server Error
# Status validation automatically fails the test if not matched
* url apiUrl
* path '/users/123'
* method get
* status 200 # Test fails if status is not 200
```gherkin
### Using responseStatus Variable
```gherkin
# Access status as variable
* def statusCode = responseStatus
* print 'Response status:', statusCode
# Complex status validation
* assert responseStatus >= 200 && responseStatus < 300
* assert responseStatus == 200 || responseStatus == 201
* if (responseStatus != 200) karate.log('Unexpected status:', responseStatus)
```gherkin
## Status Code Categories
### Success Codes (2xx)
```gherkin
Scenario: Handle success responses
* url apiUrl
* path '/users'
* method get
# Check for any success status
* assert responseStatus >= 200 && responseStatus < 300
# Handle specific success codes
* if (responseStatus == 200) karate.log('Data retrieved')
* if (responseStatus == 201) def createdId = response.id
* if (responseStatus == 204) assert response == ''
```gherkin
### Redirection Codes (3xx)
```gherkin
# Handle redirects
* configure followRedirects = false # Disable auto-follow
* url apiUrl
* path '/old-endpoint'
* method get
* if (responseStatus == 301) def newLocation = responseHeaders['Location'][0]
* if (responseStatus == 302) karate.log('Temporary redirect')
* if (responseStatus == 304) karate.log('Not modified')
# Follow redirect manually
* if (responseStatus == 301) url newLocation
* if (responseStatus == 301) method get
```gherkin
### Client Error Codes (4xx)
```gherkin
Scenario: Handle client errors
* url apiUrl
* path '/protected'
* method get
# Handle different client errors
* if (responseStatus == 400) karate.fail('Bad request: ' + response.error)
* if (responseStatus == 401) karate.call('refresh-token.feature')
* if (responseStatus == 403) karate.fail('Access forbidden')
* if (responseStatus == 404) karate.log('Resource not found')
* if (responseStatus == 429) karate.log('Rate limited, waiting...')
```gherkin
### Server Error Codes (5xx)
```gherkin
Scenario: Handle server errors
* url apiUrl
* path '/api/action'
* method post
# Server error handling
* if (responseStatus == 500) karate.fail('Server error: ' + response.message)
* if (responseStatus == 502) karate.log('Bad gateway')
* if (responseStatus == 503) karate.log('Service unavailable')
* if (responseStatus == 504) karate.log('Gateway timeout')
# Retry on server errors
* if (responseStatus >= 500) retry until responseStatus < 500
```gherkin
## Conditional Logic Based on Status
### Status-Based Workflows
```gherkin
Scenario: Conditional processing
* url apiUrl
* path '/users/', userId
* method get
# Different paths based on status
* if (responseStatus == 200) karate.call('update-user.feature', response)
* if (responseStatus == 404) karate.call('create-user.feature', { id: userId })
* if (responseStatus == 403) karate.call('request-permission.feature')
```gherkin
### Error Recovery
```gherkin
Scenario: Graceful error handling
* url apiUrl
* path '/data'
* method get
# Try primary endpoint, fallback on error
* def data = responseStatus == 200 ? response : null
# Try fallback if primary fails
* if (!data) url backupUrl
* if (!data) path '/backup/data'
* if (!data) method get
* if (!data && responseStatus == 200) def data = response
# Final validation
* assert data != null
```gherkin
### Retry Logic
```gherkin
# Built-in retry
* retry until responseStatus == 200
* path '/async/result'
* method get
# Custom retry logic
* def attemptRequest =
"""
function() {
var maxAttempts = 3;
var attempt = 0;
while (attempt < maxAttempts) {
karate.call('make-request.feature');
if (karate.get('responseStatus') == 200) {
return true;
}
attempt++;
java.lang.Thread.sleep(1000 * attempt);
}
return false;
}
"""
* def success = attemptRequest()
* assert success == true
```gherkin
## Advanced Status Validation
### Multiple Acceptable Statuses
```gherkin
# Check against list of valid statuses
* def validStatuses = [200, 201, 202]
* assert validStatuses.contains(responseStatus)
# Using switch-like logic
* def processResponse =
"""
function(status) {
switch(status) {
case 200: return 'success';
case 201: return 'created';
case 204: return 'no-content';
case 404: return 'not-found';
default: return 'unexpected';
}
}
"""
* def result = processResponse(responseStatus)
```gherkin
### Status with Response Validation
```gherkin
Scenario: Validate status and response together
* url apiUrl
* path '/users'
* method post
* request { name: 'New User' }
# Status-specific response validation
* if (responseStatus == 201) match response contains { id: '#string', created: '#string' }
* if (responseStatus == 400) match response contains { error: '#string', fields: '#array' }
* if (responseStatus == 409) match response.error == 'User already exists'
```gherkin
### Custom Status Assertions
```gherkin
# Custom status validation function
* def validateStatus =
"""
function(expected, actual) {
if (actual !== expected) {
var msg = 'Expected status ' + expected + ' but got ' + actual;
if (karate.get('response.error')) {
msg += ': ' + karate.get('response.error');
}
karate.fail(msg);
}
}
"""
* validateStatus(200, responseStatus)
```gherkin
## Status Code Testing Patterns
### Negative Testing
```gherkin
Scenario Outline: Test error handling
Given url apiUrl
And path '/test/<endpoint>'
When method <method>
Then status <expectedStatus>
And match response contains <expectedError>
Examples:
| endpoint | method | expectedStatus | expectedError |
| invalid | GET | 404 | { error: 'Not Found' } |
| unauthorized | GET | 401 | { error: 'Unauthorized' } |
| forbidden | POST | 403 | { error: 'Forbidden' } |
| bad-request | PUT | 400 | { error: '#string' } |
```gherkin
### Status Code Ranges
```gherkin
# Define status code categories
* def isSuccess = function(status) { return status >= 200 && status < 300 }
* def isRedirect = function(status) { return status >= 300 && status < 400 }
* def isClientError = function(status) { return status >= 400 && status < 500 }
* def isServerError = function(status) { return status >= 500 && status < 600 }
# Use in assertions
* assert isSuccess(responseStatus)
* if (isClientError(responseStatus)) karate.fail('Client error: ' + responseStatus)
```gherkin
### Timeout Handling
```gherkin
Scenario: Handle timeout status
* configure readTimeout = 5000 # 5 seconds
* url slowApiUrl
* path '/slow-endpoint'
* method get
# Check for timeout-related status
* if (responseStatus == 408) karate.log('Request timeout')
* if (responseStatus == 504) karate.log('Gateway timeout')
* if (responseStatus == 0) karate.fail('Connection failed')
```gherkin
## Performance Monitoring
### Response Time with Status
```gherkin
Scenario: Monitor performance by status
* url apiUrl
* path '/api/endpoint'
* method get
# Log performance metrics
* print 'Status:', responseStatus, 'Time:', responseTime, 'ms'
# Performance assertions based on status
* if (responseStatus == 200) assert responseTime < 1000
* if (responseStatus == 201) assert responseTime < 2000
# Track slow responses
* if (responseTime > 3000) karate.log('Slow response:', responseStatus, responseTime)
```gherkin
### Status Code Metrics
```gherkin
# Track status codes across tests
* def statusMetrics = { success: 0, error: 0, total: 0 }
* def trackStatus =
"""
function(status) {
statusMetrics.total++;
if (status >= 200 && status < 300) {
statusMetrics.success++;
} else {
statusMetrics.error++;
}
}
"""
# Use in tests
* url apiUrl
* path '/test'
* method get
* trackStatus(responseStatus)
# Report metrics
* print 'Status metrics:', statusMetrics
```gherkin
## Best Practices
### Clear Status Expectations
```gherkin
# ✅ Good: Explicit status validation
Scenario: Create user
* url apiUrl
* path '/users'
* request { name: 'Test User' }
* method post
* status 201 # Clearly expect created status
* match response.id == '#string'
# ❌ Avoid: No status validation
Scenario: Get user
* url apiUrl
* path '/users/123'
* method get
# Missing status check!
```gherkin
### Informative Error Messages
```gherkin
# ✅ Good: Detailed error information
* if (responseStatus != 200) karate.fail('Failed to get user. Status: ' + responseStatus + ', Error: ' + response.error)
# ✅ Good: Context in assertions
* assert responseStatus == 200 || responseStatus == 201 : 'Expected success status but got ' + responseStatus
```gherkin
### Status Documentation
```gherkin
# ✅ Good: Document expected statuses
Scenario: API status codes
"""
Expected status codes:
- 200: Success with data
- 201: Created new resource
- 204: Success with no content
- 400: Invalid request data
- 401: Authentication required
- 404: Resource not found
"""
* url apiUrl
* path endpoint
* method get
* assert [200, 404].contains(responseStatus)
```gherkin
## Next Steps
- Learn about [Response Data](/docs/http-responses/response-data) for body validation
- Explore [Headers and Cookies](/docs/http-responses/headers-cookies) for metadata handling
- Understand [Assertions](/docs/assertions/match-keyword) for comprehensive validation