On this page14 sections

REST Assured API Automation Project Sample

A complete Java API automation project sample using REST Assured, reusable request and response specifications, authentication helpers, JSON schema validation, test data builders, Allure reporting, and CI/CD.

IntermediateAPI automationRegression testingSchema validationapi automation
Setup: 30–45 minutesLanguage: Java 17Framework: REST AssuredPackage manager: MavenBest for: API testers

Overview

This REST Assured API automation project sample shows how to structure a maintainable Java-based API testing framework. It uses REST Assured for HTTP requests and assertions, Maven for dependency management, JUnit 5 for test execution, reusable request and response specifications, JSON schema validation, Allure reporting, and CI/CD execution via GitHub Actions. The project runs against Restful Booker (https://restful-booker.herokuapp.com), a free, widely-used API-testing playground that offers authentication plus full CRUD over hotel bookings. The project demonstrates how to organise clients, models, specifications, test data, schemas, utilities, and tests so API automation stays readable, reusable, and scalable.

Project goals

  • Configure REST Assured with Java 17 and Maven; set base URI and content-type once in a shared RequestSpecification so individual tests never set them inline
  • Build a reusable RequestSpecification (base headers, content-type, URI) and an AuthenticatedRequestSpec that attaches the auth token as a Cookie header — not Authorization: Bearer, which Restful Booker rejects
  • Build a reusable ResponseSpecification for common status-code and content-type assertions, reducing repeated assertion boilerplate across test methods
  • Create an API client layer (BookingClient, AuthClient) that wraps REST Assured calls so test classes interact with typed methods and never touch raw HTTP mechanics
  • Implement a TokenManager that requests the auth token once in @BeforeAll and caches it for the full suite — no per-test re-authentication
  • Build request and response model POJOs (BookingRequest, BookingResponse) with Jackson for clean serialisation and deserialisation
  • Use a TestDataBuilder to generate fresh, randomised payloads per test so no test relies on shared mutable state in the live Restful Booker database
  • Write positive CRUD tests (create, get, update, delete), negative tests (bad payloads, missing auth, invalid IDs), status code, header, and error response validation
  • Validate response schemas using JSON schema files in src/test/resources/schemas/ via REST Assured's JSON Schema Validator
  • Generate Allure Reports locally (mvn allure:serve) and upload results as a CI artifact in the GitHub Actions workflow

Architecture

Layered API Framework: Tests → Clients → Specs → Models → Config / Utils

Tests call typed client methods (BookingClient, AuthClient) rather than REST Assured directly. Clients build requests from reusable RequestSpecification and ResponseSpecification factories. POJOs handle serialisation. TokenManager manages auth state. AppConfig reads config.properties. Schemas and test data live in src/test/resources/.

tests/JUnit 5 test classes: BookingCrudTests, BookingNegativeTests, BookingSchemaTests
clients/BookingClient, AuthClient; wrap all REST Assured calls and return typed responses
specs/RequestSpecs, ResponseSpecs; reusable request/response specification factories
models/Jackson POJOs: BookingRequest, BookingResponse, BookingDates, AuthResponse
schemas/JSON Schema files for contract validation via json-schema-validator
config/AppConfig; reads config.properties, provides base URL, credentials, timeout
utils/TokenManager (auth caching), RandomDataUtil, JsonUtil, Allure step helpers
testdata/Fixed JSON fixtures for reference payloads and schema validation tests

Prerequisites

  • Java Development Kit (JDK) 17 or later — JAVA_HOME must be set
  • Maven 3.8 or later — mvn must be on PATH
  • Git
  • IDE with Maven support — IntelliJ IDEA, Eclipse, or VS Code with Java Extension Pack
  • Basic Java knowledge: classes, annotations, generics
  • Basic HTTP and REST understanding: methods, status codes, headers, request/response bodies
  • Basic JSON knowledge: structure, field types, nested objects
  • Optional: Postman or curl for manual API exploration, Allure CLI for standalone report generation

Folder structure

Project structure
Bash
pom.xml                                   # Maven build: REST Assured, JUnit 5, Jackson, Allure, JSON Schema Validator, Surefire plugin
.github/workflows/rest-assured-tests.yml  # CI workflow: checkout → Java 17 → cache Maven → mvn test → upload Allure results
src/main/java/codes/qa/api/clients/BookingClient.java  # createBooking, getBooking, updateBooking, deleteBooking — typed wrappers over REST Assured
src/main/java/codes/qa/api/clients/AuthClient.java  # Calls POST /auth and returns the token string
src/main/java/codes/qa/api/config/AppConfig.java  # Reads config.properties; typed getters for base URL, credentials, and timeout
src/main/java/codes/qa/api/specs/RequestSpecs.java  # base() and authenticated() RequestSpecification factories; authenticated() attaches token as Cookie
src/main/java/codes/qa/api/specs/ResponseSpecs.java  # Shared ResponseSpecification for 2xx status and application/json content-type assertions
src/main/java/codes/qa/api/models/BookingRequest.java  # Jackson POJO for the booking request body
src/main/java/codes/qa/api/models/BookingResponse.java  # Jackson POJO for the booking response body, including bookingid
src/main/java/codes/qa/api/models/BookingDates.java  # Nested POJO for the bookingdates object inside Booking
src/main/java/codes/qa/api/models/AuthResponse.java  # Jackson POJO for the POST /auth response (token field)
src/main/java/codes/qa/api/utils/TokenManager.java  # Requests and caches the auth token once per suite run
src/main/java/codes/qa/api/utils/RandomDataUtil.java  # Generates randomised names, prices, and dates for test data builders
src/main/resources/config.properties.example  # Config template — copy to config.properties and set base.url and credentials
src/test/java/codes/qa/api/base/BaseTest.java  # @BeforeAll token initialisation; @AfterEach cleanup of bookings created during the test
src/test/java/codes/qa/api/tests/BookingCrudTests.java  # Positive CRUD lifecycle, status code, header, and response body assertions
src/test/java/codes/qa/api/tests/BookingNegativeTests.java  # Negative scenarios: missing auth (403), invalid ID (404), bad payloads, unauthorised operations
src/test/java/codes/qa/api/tests/BookingSchemaTests.java  # JSON schema validation for all booking endpoints against schemas in src/test/resources/schemas/
src/test/resources/schemas/booking-response.json  # JSON Schema for the booking response body (GET /booking/{id})
src/test/resources/schemas/booking-list-response.json  # JSON Schema for the GET /booking list response (array of bookingid objects)
src/test/resources/testdata/booking-create.json  # Fixed reference payload for schema-focused create tests
src/test/resources/testdata/booking-update.json  # Fixed reference payload for update and partial-update tests
README.md                                 # Setup instructions, run commands, architecture overview, and portfolio guidance

Setup & run

Installation

  1. 1.Clone the repository once published: git clone <repo-url> && cd rest-assured-api-automation
  2. 2.Verify prerequisites: java -version (expect 17+) && mvn -version (expect 3.8+)
  3. 3.Copy the config template: cp src/main/resources/config.properties.example src/main/resources/config.properties
  4. 4.Set base.url=https://restful-booker.herokuapp.com in config.properties (or set QA_API_BASE_URL environment variable)
  5. 5.Resolve Maven dependencies: mvn dependency:resolve
  6. 6.Compile and confirm no errors: mvn test-compile

Commands

Run the full suite

mvn test

Runs all JUnit 5 tests and generates Allure results in target/allure-results; use mvn allure:serve to view the report. Note: commands will work once the repository is published.

Run CRUD tests only

mvn test -Dtest=BookingCrudTests

Full positive lifecycle: create → get → update → delete with value and schema assertions

Run negative tests only

mvn test -Dtest=BookingNegativeTests

Bad payloads, missing auth, invalid IDs, partial update edge cases

Run schema tests only

mvn test -Dtest=BookingSchemaTests

JSON schema validation for all booking endpoints

Override base URL

mvn test -Dbase.url=https://restful-booker.herokuapp.com

Overrides the base.url in config.properties without editing the file

View Allure report

mvn allure:serve

Opens the Allure HTML dashboard in a browser after a test run

Environment

VariableDescriptionExampleRequired
base.urlRoot URL of the API under test — set in config.properties or override with QA_API_BASE_URLhttps://restful-booker.herokuapp.comYes
QA_API_BASE_URLEnvironment variable override for base.url — takes precedence over config.properties in CIhttps://restful-booker.herokuapp.comNo
QA_API_USERNAMEUsername for POST /auth token generation — injected as a CI secretadminYes
QA_API_PASSWORDPassword for POST /auth token generation — injected as a CI secret; do not commit real valuespassword123Yes
QA_API_TIMEOUT_SECONDSHTTP connection and socket timeout in seconds — defaults to 10 if not set15No

Test data strategy

  • TestDataBuilder creates a fresh BookingRequest POJO for each test with randomised names and dates so tests are independent even against the live, stateful Restful Booker API
  • Auth token is obtained once in @BeforeAll via TokenManager and reused across all tests in the suite — no per-test re-authentication overhead
  • Tests POST their own booking and act on the returned bookingid — never assume a fixed booking ID exists in the shared Restful Booker database
  • Negative-path variants use dedicated builder methods (withMissingFirstname(), withNegativePrice()) in one place, keeping invalid payload construction out of test bodies
  • Fixed JSON fixtures in src/test/resources/testdata/ serve as stable reference payloads for schema-focused tests that need deterministic input
  • Credentials are stored in config.properties (gitignored); CI injects QA_API_USERNAME and QA_API_PASSWORD as GitHub Actions repository secrets

Reporting

  • Allure Reports is the primary reporting mechanism — annotate BookingClient methods with @Step for step-level traces visible in the Allure dashboard
  • Run mvn allure:serve after a local run to open the Allure HTML report in a browser
  • Maven Surefire generates XML and plain-text reports in target/surefire-reports on every run — always present, no extra configuration needed
  • GitHub Actions uploads target/allure-results as a downloadable artifact after every run (including failures) so results are inspectable without re-running locally

CI/CD

  • Workflow file: .github/workflows/rest-assured-tests.yml — triggers on push and pull_request to main; workflow name: 'REST Assured API Tests'
  • Step 1: actions/checkout@v4 — check out the repository
  • Step 2: actions/setup-java@v4 with java-version: '17' and distribution: 'temurin'
  • Step 3: actions/cache@v4 caches ~/.m2/repository on the pom.xml hash to avoid downloading all dependencies on every run
  • Step 4: mvn test -B runs the full suite in batch mode; Maven exits non-zero on test failure, which fails the workflow
  • QA_API_USERNAME and QA_API_PASSWORD are stored as repository secrets and passed as -DQA_API_USERNAME and -DQA_API_PASSWORD Maven properties
  • Step 5: actions/upload-artifact@v4 uploads target/allure-results with if: always() so artifacts are available even after a failing run

Common issues

403 Forbidden on PUT / PATCH / DELETE

Cause: Token sent as Authorization: Bearer <token> — Restful Booker requires a Cookie header instead

Fix: Change RequestSpecs.authenticated() to use .cookie("token", TokenManager.get()) instead of .header("Authorization", "Bearer " + token); the Bearer form is rejected

Delete test 'fails' — asserting 200 or 204 on DELETE

Cause: Restful Booker returns 201 Created on a successful DELETE — not 200 or 204 as most APIs do

Fix: Assert statusCode(201) for DELETE /booking/{id} against Restful Booker; document this quirk in a comment so future maintainers do not 'fix' it back to 204

First CI run is flaky or times out on the first test

Cause: Restful Booker runs on Heroku and cold-starts after inactivity — the first request can take 10–30 seconds

Fix: Add a @BeforeAll health-check step that polls GET /ping until it returns 201 before the suite begins; set a sane request timeout (10–15 s) in AppConfig

Negative test 'fails' — expected 400, got 200 with wrong data

Cause: Restful Booker accepts some invalid payloads and returns 200 with incorrect data rather than a 4xx

Fix: Assert on the API's actual documented behavior; validate the response body, not just the status code — a 200 with wrong data is a real bug, and this is a good real-world API testing lesson

POST /auth returns 200 with {"reason": "Bad credentials"} instead of a token

Cause: Restful Booker returns HTTP 200 even for auth failures — the error is in the body, not the status code

Fix: Assert body("token", notNullValue()) rather than on the status code alone; TokenManager should throw if the token field is absent rather than caching an empty value

JSON schema validation throws ClassNotFoundException for json-schema-validator

Cause: The json-schema-validator artifact or jackson-databind has a version conflict with the rest-assured BOM

Fix: Import io.rest-assured:rest-assured-all in pom.xml instead of individual artifacts; use a <dependencyManagement> block to align jackson-databind versions if needed

Best practices

  • Define RequestSpecification and ResponseSpecification once in factory classes — never inline base URI, headers, or common assertions in individual test methods
  • Use given().log().ifValidationFails() and then().log().ifValidationFails() rather than always logging — keeps CI output readable on passing runs
  • Assert on meaningful response fields (e.g. body("totalprice", greaterThan(0))) rather than just that the body is non-empty; a 200 with wrong data is a real bug
  • Prefer JSON schema validation for contract coverage and explicit field assertions for business-logic coverage — they serve different purposes and you need both
  • Store JSON schema files in src/test/resources/schemas/ and load them with JsonSchemaValidator.matchesJsonSchemaInClasspath() — never inline schema strings in test code
  • Create one booking per test and delete it in @AfterEach — tests must not depend on state left by other tests in a shared live API
  • Use @Step annotations on client methods for Allure so the report shows execution context; keep test methods short by delegating HTTP mechanics to the client layer
  • Annotate model POJOs with @JsonIgnoreProperties(ignoreUnknown = true) to decouple tests from API fields you do not own

Next steps

  • Add a data-driven test layer using JUnit 5 @ParameterizedTest with @MethodSource to run the same booking creation test with multiple valid and invalid payload variants
  • Wire the suite against a locally served Restful Booker Docker container so tests do not depend on the public internet in CI
  • Extend schema coverage to include error response bodies (4xx shapes) so the API contract is validated for failure paths, not only success paths
  • Add response-time assertions using REST Assured's time() extractor to catch latency regressions before they reach production
  • Integrate with Pact for consumer-driven contract testing, using this suite as the consumer and publishing contracts to a Pact Broker
  • Add a Postman or Bruno collection alongside the automated tests as living documentation of the API surface