nenzen 8aca735f8a
All checks were successful
Build, Test & Checkstyle / build (push) Successful in 41s
Fix PathItem bug (#7)
The `OpenApiService.rebuild()` method was creating a new `PathItem` for each endpoint and calling `addPathItem()`, which replaced any existing `PathItem` at that path.

Reviewed-on: #7
Co-authored-by: nenzen <nenzen@dsv.su.se>
Co-committed-by: nenzen <nenzen@dsv.su.se>
2025-11-11 10:59:24 +01:00
2025-05-22 14:44:21 +02:00
2025-03-25 13:26:36 +01:00
2025-05-22 14:44:21 +02:00
2025-11-11 10:59:24 +01:00
2025-03-26 09:49:10 +01:00
2025-03-25 13:25:25 +01:00
2025-03-25 13:26:36 +01:00
2025-03-25 13:26:36 +01:00
2025-03-25 13:26:36 +01:00
2025-03-25 13:26:36 +01:00
2025-03-25 13:26:36 +01:00
2025-03-25 13:26:36 +01:00
2025-11-03 23:38:55 +01:00

APImposter 🎭

A small, flexible API mock service designed with microservice environments in mind.


What is APImposter?

APImposter is an easy-to-use service built with Spring Boot, enabling quick mocking of API responses from various systems. It allows you to organize your mock data in YAML files.


Features

  • Structured Mock Data: Organize your mock data in YAML files.
  • Automatic URL Mapping: Automatically generates URL structure based on your folder hierarchy and YAML file names.
  • Hot Reloading: Automatically reloads mock data files when they are changed.
  • Dynamic Responses and Global Placeholders: Supports dynamic values in responses based on URL parameters and you can define global placeholders to reuse values across multiple responses and systems.
  • Conditional Responses: Return different mock responses based on request data (headers, query, body, or path).
  • Swagger UI: Automatically generated Swagger UI from YAML files.

Mocks Structure

Mocks are defined in YAML files and stored in a directory specified via application.properties. You can organize them in nested folders:

/mocks/
├── globals.yaml
├── system1/
│   ├── users.yaml
│   └── index.yaml
└── another-system/
    ├── endpoint1.yaml
    └── subdir/
        ├── endpoint2.yaml
        └── index.yaml

URL Mapping

  • /system1/users.yaml defines mocks under /system1/users/...
  • /system1/index.yaml defines mocks under/system1/...)
  • Multiple endpoints can be grouped in one file
  • Folders in the YAML file structure become part of the URL path automatically.

Grouped endpoints in users.yaml

# mocks/system1/users.yaml
- method: GET
  path: "/"
  response:
    status: 200
    body:
      users:
        - id: 1
          name: "Alice"
        - id: 2
          name: "Bob"

- method: GET
  path: "/{id}"
  response:
    status: 200
    body:
      id: "{id:int}"
      name: "User {id}"

- method: POST
  path: "/"
  response:
    status: 200
    body:
      message: "User created"

Base-level grouping via index.yaml

# mocks/system1/index.yaml
- method: GET
  path: "/"
  response:
    status: 200
    body:
      message: "Welcome to system1"

- method: GET
  path: "/info"
  response:
    status: 200
    body:
      name: "System One"
      version: "1.0"

Placeholder Type Hints

You can include optional type hints in placeholders to ensure JSON values are rendered with correct types.

Supported types

Type Placeholder Output
string {name} "Alice"
int {id:int} 42 (number)
float {price:float} 99.95
boolean {enabled:bool} true

If parsing fails (e.g. abc for an int), APImposter falls back to the original string.

Relative Date/Time Placeholders

APImposter supports dynamic date and time placeholders that are calculated relative to the current time. This is perfect for testing calendar applications, scheduling systems, or any time-sensitive mock data.

Supported formats

Format Example Description
{datetime+/-offset} {datetime+2d4h30m} DateTime with flexible time offset
{datetime+/-Nd@HH:MM} {datetime+1d@13:30} DateTime N days from now at specific time
{date+/-Nd} {date-7d} Date N days from now

Format specifiers (optional)

Add a format specifier after a colon to control the output format:

Specifier Description Example Output
iso (default) ISO standard format 2025-09-03T15:30:00
rfc3339 RFC 3339 with UTC timezone 2025-09-03T15:30:00Z
Custom pattern Any valid DateTimeFormatter pattern Sep 03, 2025

Examples

# Basic relative dates (ISO format)
- method: GET
  path: "/events"
  response:
    body:
      todayMeeting: "{datetime+0d@08:00}"        # Today at 8:00 AM
      tomorrowLunch: "{datetime+1d@13:00}"       # Tomorrow at 1:00 PM
      nextWeek: "{date+7d}"                      # Date 7 days from now
      pastEvent: "{datetime-2d4h30m}"            # 2 days, 4h, 30m ago
      yesterday: "{date-1d}"                     # Yesterday's date

# Different output formats
- method: GET
  path: "/calendar"
  response:
    body:
      # RFC3339 format
      eventTimeRfc: "{datetime+1d@15:30:rfc3339}"           # "2025-09-03T15:30:00Z"

      # Custom formats
      eventDate: "{date+1d:MMM dd, yyyy}"                   # "Sep 03, 2025"
      timeOnly: "{datetime+0d@14:30:HH:mm}"                 # "14:30"
      shortDate: "{date+7d:MM/dd/yy}"                       # "09/09/25"

Time components for offset format

  • d = days
  • h = hours
  • m = minutes

All components are optional and can be combined: {datetime+1d2h}, {datetime+30m}, {datetime-4h15m}

Note: If a custom format is invalid, the system automatically falls back to ISO format to prevent errors.


Example Requests and Responses

YAML file Request Response Example
system1/users.yaml GET /system1/users { "users": [{ "id": 1 }, { "id": 2 }] }
system1/users.yaml GET /system1/users/42 { "id": 42, "name": "User 42" }
system1/users.yaml POST /system1/users { "message": "User created" }
system1/index.yaml GET /system1 { "message": "Welcome to system1" }
system1/index.yaml GET /system1/info { "name": "System One", "version": "1.0" }
another-system/subdir/index.yaml GET /another-system/subdir/... (Defined response in file)

Globals

Global values can be defined in a dedicated file globals.yaml:

# mocks/globals.yaml
globals:
  currentUserId: "user-123"

You can reference global values using {globals.key} or {globals.key:type} in responses.


Conditional Responses

APImposter supports conditional responses, allowing different mock responses to be returned based on request values - query parameters, headers, path variables, or body fields.

This is useful for simulating realistic API behavior, such as authentication, filtering, or alternate success/error outcomes.

Supported condition types:

  • path: matches against path variables
  • query: matches query parameters (?filter=active)
  • headers: matches HTTP headers (case-insensitive)
  • body: matches top-level JSON body fields (for POST/PUT)

Example: conditionals by path

- method: "GET"
  path: "/users/{id}"
  conditionalResponses:
    - conditions:
        path:
          id: "1"
      response:
        status: 200
        headers:
          Content-Type: application/json
        body:
          id: 1
          name: "Lennart"
    - conditions:
        path:
          id: "2"
      response:
        status: 200
        headers:
          Content-Type: application/json
        body:
          id: 2
          name: "Kurre"
  response:
    status: 404
    headers:
      Content-Type: application/json
    body:
      error: "User not found"

Example: conditionals by header

- method: "GET"
  path: "/secure"
  conditionalResponses:
    - conditions:
        headers:
          authorization: "Bearer abc123"
      response:
        status: 200
        headers:
          Content-Type: application/json
        body:
          message: "Access granted"
  response:
    status: 401
    headers:
      Content-Type: application/json
    body:
      error: "Unauthorized"

Example: conditionals by query parameter

- method: "GET"
  path: "/products"
  conditionalResponses:
    - conditions:
        query:
          category: "books"
      response:
        status: 200
        headers: { Content-Type: "application/json" }
        body:
          products:
            - id: "b1"
              name: "Data Structures and Algorithms in Java"
    - conditions:
        query:
          category: "tech"
      response:
        status: 200
        headers: { Content-Type: "application/json" }
        body:
          products:
            - id: "t1"
              name: "Keyboard"
  response:
    status: 200
    headers: { Content-Type: "application/json" }
    body:
      products: []

Example: conditionals by request body

- method: "POST"
  path: "/login"
  conditionalResponses:
    - conditions:
        body:
          username: "admin"
          password: "secret"
      response:
        status: 200
        headers:
          Content-Type: application/json
        body:
          token: "abc123"
  response:
    status: 403
    headers:
      Content-Type: application/json
    body:
      error: "Invalid credentials"

Testing with curl

curl http://localhost:8080/mocks/users/1

curl -H "Authorization: Bearer abc123" http://localhost:8080/mocks/secure

curl "http://localhost:8080/mocks/products?category=books"

curl -X POST http://localhost:8080/mocks/login \
     -H "Content-Type: application/json" \
     -d '{"username": "admin", "password": "secret"}'

Conditions are evaluated in order, and the first matching block wins. If no condition matches, the fallback response: is used.


Configuration

In application.properties you can configure the following properties:

  • mock.file-path: The path to the directory containing your mock data YAML files.
  • mock.reload-interval-ms: The interval in milliseconds at which the service checks for changes in the mock data files.
  • mock.base-path: The base path for the mock service. This is prepended to all generated URLs. Default is /mocks.
  • mock.default-delay-ms: The default delay in milliseconds for responses. This can be overridden in the YAML files.

Swagger UI

OpenAPI Specification is generated from the mock data YAML files and can be accessed via Swagger UI. You will find it at:

http://localhost:8080/swagger

Quick Start

Clone the project and run it simply with:

./mvnw spring-boot:run

or with Docker:

docker-compose up

🎭 Good luck and happy mocking! 🎭

Description
No description provided
Readme 3.8 MiB
Languages
Java 99.3%
Dockerfile 0.7%