What We Are Learn:
Toggle1️⃣ Authentication & Authorization Issues
One of the most common challenges is handling different authentication mechanisms.
Real‑time scenarios:
- OAuth2 token expiry during long test runs
- Token generated successfully but not accepted by downstream services
- Role‑based APIs returning 403 Forbidden even after successful login
How I handled it:
- Automated token generation and refresh
- Validated roles/claims inside JWT tokens
- Added negative tests for invalid/expired tokens
2️⃣ Dependency on Upstream / Downstream APIs
APIs are rarely standalone; they depend on other services.
Example:
- Order API depended on Inventory API
- Inventory API was unstable in QA → Order API tests failed
Challenge:
- Hard to identify whether the defect belongs to our service or dependent service
Solution:
- Used mock services / stubs
- Isolated API testing at service level before E2E validation
3️⃣ Incomplete or Changing API Documentation
This is a very real pain point.
Real‑time issues:
- Swagger not updated
- Mandatory fields missing in documentation
- Response fields changed without notice
Impact:
- Automation scripts started failing
- False defects raised initially
Mitigation:
- Validated APIs using actual response schema
- Maintained contract test cases
- Frequent sync with dev team
4️⃣ Dynamic Response Data Validation
Validating dynamic values is tricky.
Examples:
- Auto‑generated IDs
- Timestamps
- Encrypted values
Challenge:
- Hard‑coded assertions fail
Approach:
- Validated data types, patterns, and partial matches
- Compared API response with DB values where applicable
5️⃣ Environment & Configuration Issues
APIs behave differently across environments.
Real‑time scenario:
- API worked in QA but failed in UAT due to:
- Wrong base URL
- Missing headers
- Feature flags disabled
Solution:
- Environment‑specific config files
- Health‑check APIs before execution
6️⃣ Error Handling & Negative Scenarios
APIs often return:
- Incorrect HTTP status codes
- Generic error messages
- No error body at all
Example:
- API returned
200 OKeven for invalid input
Challenge:
- Business validation vs technical validation mismatch
Action:
- Raised defects highlighting incorrect REST standards
- Added negative test cases explicitly
7️⃣ Data Setup & Cleanup
APIs require clean test data.
Issues faced:
- Duplicate data errors
- Dirty data affecting parallel execution
Solution:
- Pre‑condition APIs / DB scripts for setup
- Post‑execution cleanup
- Unique test data generation
8️⃣ Performance & Timeout Issues
During integration testing:
- APIs worked functionally but failed under load
- Random timeouts caused flaky automation results
Handling:
- Added response‑time assertions
- Coordinated with performance team early
1️⃣ Validate HTTP Status Code (First Gate)
I always start with the status code, because it tells whether the request was handled correctly at protocol level.
Examples:
200 / 201→ Successful response400→ Bad request (client issue)401 / 403→ Authentication / authorization issue500→ Server error
✅ If the status code is wrong, the response is already incorrect, even if the body looks fine.
2️⃣ Validate Response Body Structure (Schema Validation)
Next, I validate whether the response structure matches the contract (Swagger / OpenAPI).
I check:
- Mandatory fields are present
- Data types are correct (string, number, boolean)
- No unexpected fields are returned
3️⃣ Validate Business Data (Most Important)
A technically correct response can still be functionally wrong.
Real‑time example:
- API returns
200 OK - But account balance is incorrect
What I validate:
- Actual values vs expected values
- Field‑to‑field comparison
- Calculated values (totals, taxes, discounts)
4️⃣ Validate Headers & Security
I verify:
- Content‑Type (
application/json) - Authorization token presence
- Cache‑control headers (if applicable)
5️⃣ Validate Error Handling (Negative Scenarios)
For invalid inputs, I check:
- Correct error code
- Meaningful error message
- Consistent error structure
Example:
- Invalid request →
400 - Clear message like
"Invalid accountId"
6️⃣ Validate Performance & Response Time
Even if everything else is correct:
- Slow APIs are considered defective
I validate:
- Response time within SLA
- No unexpected timeouts
OAuth 1.0 secures every request using cryptographic signatures, making it complex and outdated, whereas OAuth 2.0 uses token‑based authorization with multiple grant types, making it simpler, scalable, and the industry standard for modern applications.
When the nested JSON response is dynamic (keys/arrays/order can change), I validate it in layers instead of doing hard‑coded field‑to‑field assertions.
1) Validate “contract” using JSON Schema (best baseline)
I keep a schema that enforces:
- required top‑level fields exist (
status,data, etc.) - data types are correct (string/number/boolean)
- allows unknown/dynamic fields using
additionalProperties: true - uses flexible rules for dynamic arrays (minItems, item schema)
In real API automation (Rest Assured), I’ve used jsonSchemaValidator with Hamcrest matchers for schema + key validations, especially when payload shape evolves frequently.
given()
.when().get("/orders/123")
.then()
.statusCode(200)
.body(matchesJsonSchemaInClasspath("schemas/order.schema.json"));
2) Use JSONPath with wildcards/filters for dynamic nesting
When indexes and node positions vary, I avoid fixed paths like data.items[0].id. Instead I use:
- wildcard:
items*.id/items[*].id - filter:
items.findAll { it.type == 'PRIMARY' }.id
Example:
List<String> ids = jsonPath.getList("data.items.findAll { it.active == true }.id");
assertThat(ids, not(empty()));
For arrays of JSON objects, I extract fields using JSONPath/JS mapping and validate based on conditions (find/filter) and invariants (every item has required fields), instead of relying on fixed indexes—this makes tests stable even when data is dynamic.
Response res = given().when().get("/users");
List<Integer> ids = res.jsonPath().getList("users.id");
assertThat(ids, hasSize(greaterThan(0)));
When an API field returns dynamic data types, I validate it using conditional type checks or flexible JSON schema (oneOf), normalize values for assertions, and flag inconsistent typing as a design concern if it violates the API contract.
I extract the field and check its runtime type, then validate accordingly.
Object amount = response.jsonPath().get("data.amount");
if (amount instanceof Integer || amount instanceof Float || amount instanceof Double) {
assertThat(((Number) amount).doubleValue(), greaterThan(0.0));
} else if (amount instanceof String) {
assertThat((String) amount, matchesPattern("\\d+(\\.\\d+)?"));
} else if (amount == null) {
// allowed scenario
} else {
fail("Unexpected data type for amount");
}
First: Confirm Rate‑Limit Policy (Very Important)
Before automation changes, I validate:
- Requests per second/minute allowed
- Burst limits
- Cool‑down window
- Whether limits differ per environment (QA vs PROD)
This aligns with traffic management and throttling practices recommended in enterprise API guidelines.
✅ If limits are undocumented → I raise a clarification request.
Respect Retry‑After Header (Best Practice)
Most APIs return a Retry-After header with 429.
✅ Correct handling:
- Read
Retry‑After - Wait for that duration
- Retry the request
Example (Rest Assured / Java – pseudo logic)
if (response.statusCode() == 429) {
int waitTime = Integer.parseInt(response.getHeader("Retry-After"));
Thread.sleep(waitTime * 1000);
retryRequest();
}
✅ What is a multipart/form-data response?
A multipart/form-data response contains multiple parts in a single HTTP response, separated by boundaries.
Each part can have:
- Its own headers
- Its own content type (JSON, XML, file, text, binary)
Typical real‑world examples:
- File download + metadata JSON
- PDF + status info
- Image + validation response
- Multiple files in one response
✅ My Overall Strategy
I never treat multipart responses as plain JSON.
Instead, I:
- Validate headers and boundaries
- Split the response into parts
- Validate each part independently
- Apply content‑specific assertions
1️⃣ Validate Response Headers First
Before parsing the body, I validate:
- HTTP status code
Content-Typecontainsmultipart/form-data- Presence of a
boundary
✅ Example check:
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXYZ
What Is an API?
An API (Application Programming Interface) is a contract or interface that allows two software components to communicate with each other.
It defines how requests should be made, what data is expected, and what response will be returned.
Key points:
- APIs can be local or remote
- They can use any protocol (HTTP, TCP, gRPC, WebSockets, or even in‑process method calls)
- Data formats can be JSON, XML, binary, or custom
- APIs are not limited to the web
Example:
- A Java library method
- An OS file system API
- A REST API used by a mobile app
What Is a Web Service?
A Web Service is a specific type of API that:
- Always works over a network
- Uses web protocols like HTTP/HTTPS
- Is designed for machine‑to‑machine communication over the internet
Common types of web services:
- SOAP (XML‑based, strict standards)
- RESTful services (JSON/XML over HTTP)
Key point:
Protocols Used in API Testing
1. HTTP / HTTPS
This is the most commonly used protocol for API testing.
- Used by REST, SOAP, GraphQL APIs
- Supports standard HTTP methods:
GET,POST,PUT,DELETE,PATCH - HTTPS adds encryption using TLS/SSL
Used for:
Web APIs, microservices, public and internal APIs
REST (Representational State Transfer)
REST is an architectural style built on top of HTTP/HTTPS.
- Stateless communication
- Uses JSON or XML payloads
- Resource‑based endpoints
1️⃣ Request Validation
Verify that the API correctly handles incoming requests:
- Correct HTTP method (
GET,POST,PUT,DELETE) - Mandatory and optional request parameters
- Request headers (Content‑Type, Authorization, Accept)
- Request payload structure and data types
- Boundary values and invalid inputs
2️⃣ Response Validation
Ensure the API response is correct and consistent:
- HTTP status codes (
200,201,400,401,403,404,500) - Response body structure (JSON / XML)
- Field names, data types, and values
- Mandatory vs optional response fields
- Null and empty values handling
3️⃣ Business Logic Validation
Confirm the API enforces business rules correctly:
- Correct calculations and transformations
- Conditional flows based on input data
- Data consistency across multiple APIs
- Validation of success and failure scenarios
- Correct error messages for business rule violations
4️⃣ Data Integrity & Database Validation
Verify backend data accuracy:
- Data is correctly inserted, updated, or deleted in DB
- No duplicate or inconsistent records
- Correct data mapping between request and database
- Transaction handling (commit / rollback)
- Data consistency across integrated systems
5️⃣ Error Handling & Negative Scenarios
Validate how the API behaves under failure conditions:
- Invalid inputs and missing parameters
- Unauthorized and forbidden access
- Proper error codes and messages
- No sensitive information exposed in errors
- Graceful handling of unexpected failures
6️⃣ Authentication & Authorization
Ensure API security is enforced:
- API keys, tokens, OAuth, or basic authentication
- Token expiry and refresh handling
- Role‑based access control
- Unauthorized users cannot access protected endpoints
7️⃣ Performance & Reliability
Check API stability and speed:
- Response time under normal load
- Behavior under high concurrency
- Rate limiting and throttling
- Timeout handling
- Stability during long‑running requests
8️⃣ Integration Validation
Validate interaction with dependent systems:
- Downstream service calls
- Third‑party integrations
- Message queues or event triggers
- Proper fallback when dependencies are unavailable
9️⃣ Schema & Contract Validation
Ensure API contract compliance:
- API follows defined contract (Swagger / OpenAPI)
- Backward compatibility
- Versioning behavior
- Field deprecation handling
🔟 Security Testing
Verify API is not vulnerable:
- SQL injection and script injection
- Input validation
- HTTPS enforcement
- Sensitive data masking
- Header security checks
What is an API?
An API (Application Programming Interface) is a general interface or contract that allows software components to communicate. APIs can work locally or remotely, and they are not limited to the web. They can use multiple protocols and data formats.
What is a Web Service?
A Web Service is a specific type of API that always communicates over a network, using web protocols such as HTTP/HTTPS. It follows web standards and is designed for interoperability between systems over the internet.
🔹 What is SOAP?
SOAP (Simple Object Access Protocol) is a strict, protocol‑based approach for building APIs. It relies heavily on XML and follows a formal contract (WSDL) that defines how the service should behave. SOAP is designed with enterprise‑level security, reliability, and transactional integrity in mind.
🔹 What is REST?
REST (Representational State Transfer) is an architectural style, not a protocol. REST APIs are built on top of HTTP/HTTPS, are lightweight, and commonly use JSON for data exchange. REST focuses on simplicity, scalability, and performance.
✅ What Is JSON?
JSON (JavaScript Object Notation) is a lightweight data‑interchange format used to represent and exchange data between systems.
Key points:
- Holds actual data
- Human‑readable and machine‑parsable
- Used in API requests, responses, config files
- No built‑in validation rules
Example (JSON data):
{
"name": "Alice",
"age": 30,
"isActive": true
}
JSON only represents data—it does not define whether the data is valid or complete.
✅ What Is JSON Schema?
JSON Schema is a specification (written in JSON) that defines rules, structure, and constraints for JSON data.
Key points:
- Acts as a blueprint or contract
- Defines data types, required fields, limits, patterns
- Used for validation, documentation, and API contracts
- Ensures data consistency and integrity
Example (JSON Schema):
{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer", "minimum": 0 }
},
"required": ["name", "age"]
}
This schema validates whether incoming JSON matches the expected structure.
🔹 Path Parameters
Path parameters are part of the URL path and are used to identify a specific resource.
Key characteristics:
- Mandatory
- Identify which resource is being accessed
- Usually represent IDs or unique values
- Appear inside the URL path
Example:
GET /users/101
- 101 is a path parameter
- It uniquely identifies a user
🔹 Query Parameters
Query parameters are used to filter, sort, paginate, or modify the response.
Key characteristics:
- Optional
- Do not identify the resource
- Used for searching, filtering, pagination
- Appear after
?in the URL
Example:
GET /users?role=admin&page=2
roleandpageare query parameters.- They refine the result set
Handling Timeouts in Rest Assured
Timeouts prevent tests from hanging indefinitely when an API is slow or unresponsive. Rest Assured uses Apache HTTP Client, so timeouts are configured at the HTTP‑client level.
🔹 Types of Timeouts
- Connection Timeout – Time to establish a connection
- Socket (Read) Timeout – Time to wait for response data
- Connection Request Timeout – Time to get a connection from pool
import io.restassured.RestAssured;
import io.restassured.config.HttpClientConfig;
import io.restassured.config.RestAssuredConfig;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000) // connection timeout
.setSocketTimeout(5000) // read timeout
.build();
RestAssured.config = RestAssuredConfig.config()
.httpClient(HttpClientConfig.httpClientConfig()
.httpClientFactory(() ->
HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.build()));
This ensures tests fail fast when APIs exceed expected response times.
Handling Retries in Rest Assured
Rest Assured does not provide built‑in retry support, so retries are implemented using custom logic or helper libraries.
int maxRetries = 3;
int delay = 2000;
for (int attempt = 1; attempt <= maxRetries; attempt++) {
Response response = RestAssured.get("https://api.example.com/resource");
if (response.getStatusCode() == 200) {
break;
}
Thread.sleep(delay);
}
1. Validate Against a Set of Acceptable Status Codes
Instead of asserting a single value, validate against allowed outcomes.
int statusCode =
given()
.when()
.post("/orders")
.getStatusCode();
assertThat(statusCode,
anyOf(is(200), is(201), is(202)));
2. Conditional Assertions Based on Status Code
Assert different validations depending on the response.
Response response =
given()
.when()
.get("/payment/status");
int status = response.getStatusCode();
if (status == 200) {
response.then().body("status", equalTo("COMPLETED"));
} else if (status == 202) {
response.then().body("status", equalTo("IN_PROGRESS"));
} else {
fail("Unexpected status code: " + status);
}