API Testing with Robot Framework RESTinstance: Beyond SeleniumLibrary
Browser automation gets most of the attention in Robot Framework discussions, but API testing is where keyword-driven testing often delivers the fastest return. APIs are deterministic, fast to execute, and free from the timing complexity that makes UI tests flaky. A well-designed API test suite runs in seconds, covers backend logic exhaustively, and gives you confidence before a single UI test runs.
RESTinstance is the Robot Framework library built specifically for REST API testing. It goes beyond simple HTTP calls — it provides JSON schema validation, instance-level response tracking, and a natural keyword syntax that makes test cases readable without sacrificing technical precision.
Why RESTinstance Over Requests Library
Python's requests library is excellent, and the robotframework-requests wrapper (RequestsLibrary) makes it usable in Robot Framework. So why choose RESTinstance?
The key difference is how each library handles responses. RequestsLibrary gives you raw HTTP responses and expects you to write Python or Robot Framework expressions to extract and validate data. RESTinstance stores the last response as an "instance" — a structured object you query with keywords rather than expressions. This produces more readable tests:
RequestsLibrary style:
${response}= GET ${BASE_URL}/api/orders/123
${status}= Get From Dictionary ${response.json()} status
Should Be Equal ${status} shipped
${items}= Get From Dictionary ${response.json()} items
Length Should Be ${items} 3RESTinstance style:
GET /api/orders/123
Integer response body status 200
String response body status shipped
Array response body items
Integer response body items 0 quantity 2RESTinstance's instance model also enables schema validation against JSON Schema files — a killer feature for API contract testing that RequestsLibrary requires significant custom code to match.
Installation and Setup
pip install robotframework-restinstanceRESTinstance requires no external runtime dependencies beyond Python. Configure it in a resource file:
# resources/api_setup.resource
*** Settings ***
Library REST ${API_BASE_URL}
... ssl_verify=True
... loglevel=DEBUG
*** Variables ***
${API_BASE_URL} https://api.example.com
${API_VERSION} /v2
*** Keywords ***
Configure API Client
[Documentation] Sets default headers for all API requests.
Set Headers {"Content-Type": "application/json", "Accept": "application/json"}
Set Bearer Token
[Arguments] ${token}
Set Headers {"Authorization": "Bearer ${token}"}
Set API Key Authentication
[Arguments] ${api_key}
Set Headers {"X-API-Key": "${api_key}"}The REST library constructor takes the base URL — all subsequent request keywords use paths relative to this base.
CRUD Test Patterns
A complete CRUD test suite demonstrates RESTinstance's instance model clearly. The pattern: create a resource, read it back, update it, verify the update, then delete it and verify deletion.
# tests/api/orders_crud_tests.robot
*** Settings ***
Resource ../../resources/api_setup.resource
Suite Setup Authenticate And Configure Client
Test Tags api orders
*** Variables ***
${NEW_ORDER_PAYLOAD} {
... "customer_id": "cust_abc123",
... "items": [
... {"sku": "WIDGET-001", "quantity": 2, "unit_price": 29.99},
... {"sku": "GADGET-007", "quantity": 1, "unit_price": 149.00}
... ],
... "shipping_address": {
... "street": "123 Test Lane",
... "city": "Austin",
... "state": "TX",
... "zip": "78701"
... }
... }
*** Test Cases ***
Create Order Returns 201 With Order ID
POST /v2/orders ${NEW_ORDER_PAYLOAD}
Integer response status 201
String response body id
String response body status pending
Number response body total_amount 208.98
${order_id}= Output response body id
Set Suite Variable ${CREATED_ORDER_ID} ${order_id}
Get Order Returns Full Order Details
GET /v2/orders/${CREATED_ORDER_ID}
Integer response status 200
String response body id ${CREATED_ORDER_ID}
String response body customer_id cust_abc123
Array response body items
Integer response body items 0 quantity 2
String response body items 0 sku WIDGET-001
Update Order Status Changes To Processing
PATCH /v2/orders/${CREATED_ORDER_ID} {"status": "processing"}
Integer response status 200
String response body status processing
# Verify updated_at timestamp changed
String response body updated_at
Delete Order Returns 204
DELETE /v2/orders/${CREATED_ORDER_ID}
Integer response status 204
Deleted Order Returns 404
GET /v2/orders/${CREATED_ORDER_ID}
Integer response status 404
String response body error Order not foundThe Output keyword extracts a value from the current response instance for use in subsequent tests. Set Suite Variable makes it available across test cases in the suite — this is how you chain CRUD operations where each step depends on the result of the previous one.
JSON Schema Validation
Schema validation is RESTinstance's most powerful feature for API contract testing. Instead of asserting individual fields, validate the entire response structure against a JSON Schema:
// schemas/order_response.json
{
"$schema": "http://json-schema.org/draft-07/schema",
"type": "object",
"required": ["id", "status", "customer_id", "items", "total_amount", "created_at"],
"properties": {
"id": {
"type": "string",
"pattern": "^ord_[a-zA-Z0-9]{12}$"
},
"status": {
"type": "string",
"enum": ["pending", "processing", "shipped", "delivered", "cancelled"]
},
"customer_id": {"type": "string"},
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["sku", "quantity", "unit_price"],
"properties": {
"sku": {"type": "string"},
"quantity": {"type": "integer", "minimum": 1},
"unit_price": {"type": "number", "minimum": 0}
}
}
},
"total_amount": {"type": "number", "minimum": 0},
"created_at": {"type": "string", "format": "date-time"}
}
}Use it in tests:
*** Keywords ***
Order Response Should Match Schema
[Arguments] ${order_id}
GET /v2/orders/${order_id}
Integer response status 200
Object response body schema=${CURDIR}/../../schemas/order_response.json
Validate All Order List Items Match Schema
GET /v2/orders?limit=10
Integer response status 200
Array response body data
# Validate schema for each item in the array
FOR ${index} IN RANGE 0 10
${item}= Output response body data ${index}
Run Keyword If '${item}' != 'None'
... Object response body data ${index}
... schema=${CURDIR}/../../schemas/order_response.json
ENDSchema validation catches entire classes of API regressions automatically: missing required fields, wrong types, values outside expected enums, malformed IDs. This is the closest Robot Framework gets to consumer-driven contract testing without bringing in a dedicated tool like Pact.
Authentication Flows
Most APIs require authentication. RESTinstance handles several patterns cleanly.
Bearer Token Authentication
*** Keywords ***
Authenticate And Configure Client
# Get token via login endpoint
POST /v2/auth/login {"email": "${API_USER}", "password": "${API_PASS}"}
Integer response status 200
String response body token_type Bearer
${token}= Output response body access_token
${expires_in}= Output response body expires_in
Set Bearer Token ${token}
Log Authenticated. Token expires in ${expires_in}s.
Reauthenticate If Token Expired
GET /v2/auth/verify
${status}= Output response status
Run Keyword If '${status}' == '401' Authenticate And Configure ClientAPI Key Authentication
*** Keywords ***
Configure With API Key
[Arguments] ${key_env_var}=API_KEY
${api_key}= Get Environment Variable ${key_env_var}
Set API Key Authentication ${api_key}
Test API Key Scopes
# Test that read-only key cannot write
Configure With API Key READONLY_API_KEY
POST /v2/orders ${NEW_ORDER_PAYLOAD}
Integer response status 403
String response body error Insufficient permissions
# Restore full-access key for remaining tests
Configure With API Key ADMIN_API_KEYOAuth2 Client Credentials
*** Keywords ***
Get OAuth2 Client Token
${payload}= Set Variable
... grant_type=client_credentials&client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}
Set Headers {"Content-Type": "application/x-www-form-urlencoded"}
POST /oauth/token ${payload}
Integer response status 200
${token}= Output response body access_token
Set Headers {"Content-Type": "application/json"}
Set Bearer Token ${token}Chaining Requests
Real API test scenarios rarely test endpoints in isolation — you create a user, then create an order for that user, then verify the order appears in the user's history. RESTinstance's Output keyword is the primary tool for chaining:
*** Test Cases ***
Full Order Lifecycle With Customer
[Documentation] Creates a customer, places an order, and verifies the order
... appears in the customer's order history.
# Step 1: Create customer
POST /v2/customers {"name": "Jane Smith", "email": "jane.${RANDOM}@example.com"}
Integer response status 201
${customer_id}= Output response body id
# Step 2: Place order for this customer
${order_payload}= Set Variable
... {"customer_id": "${customer_id}", "items": [{"sku": "WIDGET-001", "quantity": 1, "unit_price": 29.99}]}
POST /v2/orders ${order_payload}
Integer response status 201
${order_id}= Output response body id
# Step 3: Verify order appears in customer history
GET /v2/customers/${customer_id}/orders
Integer response status 200
Array response body data
# Find our order in the list
${found}= Run Keyword And Return Status
... String response body data 0 id ${order_id}
Should Be True ${found} msg=Order ${order_id} not found in customer historyHandling Pagination
*** Keywords ***
Get All Orders Across Pages
[Documentation] Collects all orders by following pagination links.
@{all_orders}= Create List
${page}= Set Variable 1
WHILE True
GET /v2/orders?page=${page}&limit=50
Integer response status 200
${items}= Output response body data
${count}= Get Length ${items}
Exit For Loop If ${count} == 0
Append To List ${all_orders} @{items}
${has_next}= Run Keyword And Return Status
... Boolean response body pagination has_next true
Exit For Loop If not ${has_next}
${page}= Evaluate ${page} + 1
END
[Return] @{all_orders}Comparing RESTinstance with RequestsLibrary
When should you reach for RequestsLibrary instead? The library choice comes down to team preference and test complexity:
Choose RESTinstance when:
- You want JSON schema contract validation
- Test cases should be readable by non-engineers
- You're testing standard REST APIs with JSON responses
- You want the instance model (last response always available via
Output)
Choose RequestsLibrary when:
- You need fine-grained control over raw HTTP response objects
- Working with binary responses, file downloads, or multipart uploads
- You need session-based cookie handling across requests
- The team is comfortable with Python-style response manipulation
Many teams use both: RESTinstance for standard CRUD and contract tests, RequestsLibrary for edge cases requiring low-level HTTP control.
Integrating with HelpMeTest
HelpMeTest's AI-powered test generation supports API testing patterns, generating Robot Framework test suites that cover happy paths, error scenarios, and boundary conditions from API specification documents (OpenAPI/Swagger). The generated tests use keyword patterns similar to those described here, providing a starting structure that your team can extend with custom validation logic and schema files.
For teams managing both UI and API tests in Robot Framework, this integration means a single test runner, unified reporting, and consistent keyword patterns across the full test stack.
Error Scenario Testing
Never limit API tests to happy paths. Error scenarios reveal integration bugs that don't appear in success cases:
*** Test Cases ***
Missing Required Field Returns 400 With Field Name
POST /v2/orders {"customer_id": "cust_abc123"}
Integer response status 400
String response body error Validation failed
Array response body validation_errors
String response body validation_errors 0 field items
String response body validation_errors 0 message items is required
Invalid Customer ID Returns 422
POST /v2/orders {"customer_id": "nonexistent", "items": [{"sku": "X", "quantity": 1, "unit_price": 10}]}
Integer response status 422
String response body error Customer not found
Rate Limit Returns 429 With Retry Header
# Exceed the rate limit
FOR ${i} IN RANGE 101
GET /v2/orders
END
Integer response status 429
String response headers Retry-AfterConclusion
RESTinstance brings Robot Framework's keyword-driven readability to API testing without sacrificing the technical depth that serious API test suites require. Schema validation, request chaining, and clean authentication patterns give you the tools to build an API test suite that catches regressions before they reach production.
Combined with UI tests using SeleniumLibrary or the Playwright-based Browser library, a Robot Framework API test suite becomes the fast, reliable foundation layer that makes your overall test strategy credible — fast enough to run on every pull request, thorough enough to catch the regressions that matter.