Gherkin isn't only for UI tests. When API behaviour needs to be readable by product owners or shared with manual testers, you can write API tests as BDD scenarios. There are two main approaches in Java: Karate DSL, where the feature file is the test, and Cucumber with REST Assured, where Gherkin steps call your existing Java code.
When BDD Helps API Testing
BDD feature files are readable by non-technical stakeholders (BA, PO, QA Manager).
They serve as living documentation — always up to date because they ARE the tests.
Karate DSL is the most popular BDD framework for pure API testing.
Cucumber + RestAssured is the hybrid approach if your team already uses Cucumber for UI.
Karate DSL
<!-- pom.xml -->
<dependency>
<groupId>com.intuit.karate</groupId>
<artifactId>karate-junit5</artifactId>
<version>1.4.1</version>
<scope>test</scope>
</dependency>
# order-api.feature — complete API test in Gherkin (no Java code needed!)
Feature: Order API
Background:
* url baseUrl
* def token = call read('classpath:auth/get-token.feature')
* header Authorization = 'Bearer ' + token.access_token
Scenario: Create order successfully
Given path '/api/orders'
And request { "userId": 42, "items": [{ "productId": 101, "qty": 2 }] }
When method POST
Then status 201
And match response.id == '#notnull'
And match response.status == "PENDING"
And match response.totalAmount == "#number"
* def orderId = response.id
Scenario: Get order returns correct data
Given path '/api/orders/' + orderId
When method GET
Then status 200
And match response.id == orderId
And match response.status == "PENDING"
Scenario: Create order with invalid data returns 422
Given path '/api/orders'
And request { "userId": -1, "items": [] }
When method POST
Then status 422
And match response.error.code == "VALIDATION_ERROR"
Scenario Outline: RBAC — <role> gets <expectedStatus> for admin endpoint
* def userToken = karate.callSingle('classpath:auth/get-token.feature', { role: '<role>' })
Given path '/api/admin/users'
And header Authorization = 'Bearer ' + userToken.access_token
When method GET
Then status <expectedStatus>
Examples:
| role | expectedStatus |
| admin | 200 |
| customer | 403 |
Cucumber + REST Assured
# order.feature — Cucumber feature file
Feature: Order Management
@smoke @api
Scenario: Create order and verify it appears in order list
Given I am authenticated as a "customer"
When I create an order with 2 units of product "PROD-101"
Then the response status should be 201
And the response should contain an order id
And the order status should be "PENDING"
When I retrieve the order by id
Then the order status should still be "PENDING"
// OrderStepDefinitions.java
@Given("I am authenticated as a {string}")
public void authenticateAs(String role) {
this.spec = new RequestSpecBuilder()
.addRequestSpecification(ApiConfig.baseSpec())
.addHeader("Authorization", "Bearer " + TokenManager.getToken(role))
.build();
}
@When("I create an order with {int} units of product {string}")
public void createOrder(int qty, String productId) {
this.response = given().spec(spec)
.body(Map.of("items", List.of(Map.of("productId", productId, "qty", qty))))
.when().post("/api/orders");
}
@Then("the response status should be {int}")
public void verifyStatus(int expectedStatus) {
assertThat(response.getStatusCode()).isEqualTo(expectedStatus);
}
@And("the order status should be {string}")
public void verifyOrderStatus(String expectedStatus) {
assertThat(response.jsonPath().getString("status")).isEqualTo(expectedStatus);
}
Karate or Cucumber + REST Assured?
| Karate DSL | Cucumber + REST Assured | |
|---|---|---|
| Step definitions | None: built-in HTTP and JSON steps | You write them in Java |
| Learning curve | Low for API-only tests | Needs Java and Cucumber skills |
| Reuse of existing Java framework | Limited (can call Java) | Full: POJOs, specs, clients, DB helpers |
| UI and API in one suite | Possible but less common | Natural with Selenium in the same project |
| Extras | Built-in parallel runs, mocks and performance via Gatling | Whatever your Java stack provides |
Pick Karate for a fast, API-only suite; pick Cucumber with REST Assured when you already have a Java framework or need UI and API steps together.
FAQs
Does Karate need step definitions?
No. Karate provides built-in steps for HTTP calls, JSON and XML matching, and variables, so a feature file is directly executable.
Can Cucumber be used for API testing?
Yes. Write Gherkin scenarios and implement the steps with REST Assured, sharing the response between steps through a context object injected with PicoContainer.
Is Karate better than REST Assured?
Neither is better for every team: Karate is quicker for API-only suites written by non-developers, while REST Assured fits teams with a Java framework that need full control.