Python Rest from OAS Simulator (PyROS)

This project is publicly accessible. Click to access.

Published:

10 minute read

In One Sentence

PyROS reads an OpenAPI Specification (OAS) YAML file and instantly spins up a fake REST server with every path and method registered — so frontend and QA can test against the API contract before the real backend exists.

The Problem

Vehicle software teams need to test against APIs still in development. Waiting for the backend blocks frontend and QA in parallel. Hand-written mock servers drift from the spec. Teams need mocks generated directly from the API design document — with the ability to override responses for error scenarios without redeploying code.


Six Core Capabilities

1. OAS-Driven Dynamic Endpoint Generation

Pain point: Manually creating mock routes for a 50-path OpenAPI spec is tedious and guaranteed to miss endpoints when the spec updates.

What PyROS does:

  • Parser (APIInterpreter.extract_api_requests) uses PyYAML safe_load to walk every entry under paths.
  • Extracts HTTP verbs per path (lowercase YAML keys → uppercased methods: GET, POST, PUT, DELETE).
  • Path-parameter enum expansion (EndpointFactory): scans parameters where in: path and schema.enum is defined; generates Cartesian product of all enum values into concrete URLs.
    • Example: {entity-collection} with enum [areas, components, apps, functions]/areas, /components, /apps, /functions.
  • Non-enum paths registered as literal URL templates with {param} placeholders (e.g. /{entity-collection}/{entity-id}).
  • Template matching at request time: segment-by-segment match; {param} segments match any value; length must match.
  • Bulk load from OAS:
    • POST /simulate_postman — server-side YAML file path
    • POST /simulate_postman_content — raw YAML string in request body (used by GUI)
    • CLI: python pyros/pyros.py --yaml /path/to/spec.yaml — background thread bulk-registers via self-calls to localhost:6767
  • Bundled sample spec: pyros/openapis/api.yaml — OpenAPI 3.0.0, ASAM SOVD (Service-Oriented Vehicle Diagnostic) API v1.0.4.

2. Runtime Custom Responses — No Restart Required

Pain point: Testing error paths (404, 500, malformed payloads) requires code changes and redeployment on traditional mock servers.

What PyROS does:

  • Default mock response: HTTP 200 + JSON message: "{METHOD} Successful! No custom response set."
  • Custom response model: RestResponse(http_code, json_body) per endpoint + HTTP method.
  • Set/update: POST /add_custom_response{ url, method, http_code, json_body }.
  • List: GET /list_custom_responses — returns { url: [methods with overrides] }.
  • Delete: POST /delete_custom_response{ url, method }.
  • Priority: custom response for a method wins over default; wrong method → HTTP 405; unknown URL → HTTP 404.
  • JSON wrapping: dict bodies returned as-is; non-dict values wrapped as { "data": body }.
  • Use cases: simulate 404/500/error payloads, edge-case data, arbitrary status codes (Postman example deliberately uses HTTP 330).

3. Full REST Control Plane for CI/CD

Pain point: GUI tools cannot be scripted in automated pipelines; CI needs programmatic mock setup.

What PyROS does:

Complete management API alongside mock routes:

EndpointMethodPurpose
/add_dynamic_endpointPOSTRegister mock route + allowed methods
/update_endpointPOSTRename URL and/or change methods; migrates custom responses
/delete_endpointPOSTRemove mock route and its custom-response index
/add_custom_responsePOSTOverride status + JSON body for url+method
/delete_custom_responsePOSTRemove one override
/list_endpointsGETAll registered routes → { url: [methods] }
/list_custom_responsesGETAll overrides → { url: [methods] }
/simulate_postmanPOSTBulk register from server-side YAML path
/simulate_postman_contentPOSTBulk register from YAML text
/shutdownPOSTGraceful server shutdown
/{anything}GET/POST/PUT/DELETEServes mock responses
  • Runtime registration — add/edit/delete endpoints and responses without server restart.
  • In-memory state — all endpoints live in process memory (restart clears everything; suitable for test sessions).
  • Postman collection included (PyROS.postman_collection.json) with example SOVD-style payloads — drop-in manual and automated testing.

4. Tkinter GUI — Visual Mock Management

Pain point: Testers and developers who prefer visual tools need a way to load specs and tweak responses without writing HTTP requests.

What PyROS does:

  • "PyROS API Manager" desktop app (1100×800) built with Tkinter + ttk.
  • Connect flow: modal dialog; default URL http://127.0.0.1:6767; validates via GET /list_custom_responses.
  • YAML panel:
    • File browser (initial dir /data — matches Docker volume mount)
    • LoadPOST /simulate_postman_content with file contents
  • API Endpoints panel:
    • Scrollable list: url [methods: GET, POST, …]
    • Refresh → GET /list_endpoints
    • Right-click: Add Custom Response, Delete API, Edit API
    • Add API dialog: URL + multi-select methods
  • Custom Responses panel:
    • Lists url [METHOD] pairs
    • Double-click → live HTTP call to mock endpoint; shows status + JSON in response pane
    • Right-click: Edit / Delete
    • Add/edit dialog: endpoint, method, HTTP code, JSON body with example template
  • Edit API: rename URL and change methods via POST /update_endpoint.
  • Remote-friendly: designed for Docker with X11 forwarding (DISPLAY, /tmp/.X11-unix mount).

5. Docker-First Deployment

Pain point: Mock servers need to run consistently across developer machines and CI environments without Python dependency conflicts.

What PyROS does:

  • Docker Compose build and run from repo root:
    docker compose build pyros
    docker compose up pyros
    
  • Dockerfile (Ubuntu 22.04):
    • System packages: python3, pip, curl, tcpdump, net-tools, python3-tk, x11-apps, xauth
    • Multi-stage: base (deps) → pyros (app copy)
    • Entrypoint: ./scripts/start_pyros_server.shpython3 -u pyros/pyros.py
  • Port 6767 exposed; container name pyros.
  • Volume mounts:
    • ./pyros/openapis:/data — OAS files accessible to GUI browse and server-side paths
    • /tmp/.X11-unix:/tmp/.X11-unix — X11 for GUI
  • Run GUI in container: docker exec -it pyros bash then ./scripts/start_pyros_gui.sh.
  • FastAPI + Uvicorn ASGI server on 0.0.0.0:6767.

6. Automotive SOVD Context & Testing Integration

Pain point: Vehicle connectivity APIs (diagnostics, entity collections, authorisation flows) have complex path structures that are hard to mock by hand.

What PyROS does:

  • Built at JLR Hackathon 5.0 for vehicle software / SOVD-style REST testing.
  • Bundled SOVD spec demonstrates real-world complexity — entity collections, nested resource paths, authorisation endpoints.
  • Request resolution order:
    1. Match URL template (segment-by-segment with {param} wildcards)
    2. If custom response exists for method → return it
    3. Else if method in allowed list → default 200 success message
    4. Else → 405 Method Not Allowed / 404 Not Found
  • Postman collection with SOVD-style example: /functions/123/operations/333/executions/440 with custom PUT body.
  • Programmatic control API is the integration surface for BDD frameworks — testers write steps that call /add_custom_response, /list_endpoints, etc. without GUI interaction.
  • PlantUML design doc (pyros_design.puml) documents the full pipeline: YAML → APIInterpreter → EndpointFactory → DynamicEndpointAPI → FastAPI.

Real-World Impact

Built at JLR Hackathon 5.0. Directly relevant to vehicle connectivity and diagnostics testing — enables parallel frontend/QA workstreams before backend services exist. The "generate mocks from spec, override at runtime" pattern applies to any OpenAPI-driven API development.

Skills Demonstrated

AreaWhat this project shows
API testingOpenAPI parsing, dynamic mock routing, template URL matching
PythonFastAPI, Uvicorn, PyYAML, Tkinter GUI
DevOpsDocker Compose, Ubuntu 22.04, X11 GUI forwarding, volume mounts
AutomotiveJLR hackathon, SOVD diagnostic API contract testing
Team toolingPostman collection, REST control plane for CI integration

How It Works (Plain English)

  1. Load OpenAPI YAML — file path, raw content, or CLI --yaml flag.
  2. Parser walks paths → extracts methods + path-param enums.
  3. Factory expands enums into concrete routes; FastAPI registers every endpoint.
  4. Testers hit mock URLs — default 200 response or your custom override.
  5. Change behaviour at runtime via GUI, Postman, or REST API — no code deploy, no restart.

Architecture

┌──────────────────┐     REST API      ┌─────────────────────────┐
│  Tkinter GUI     │◄─────────────────►│  Mock Server (FastAPI)  │
│  Load OAS · Edit │                   │  Dynamic routing from   │
│  responses       │                   │  OpenAPI spec           │
└──────────────────┘                   └───────────┬─────────────┘
                                                   │
              ┌────────────────────────────────────┼──────────────┐
              ▼                    ▼                 ▼              ▼
        Postman testers      CI scripts        Frontend dev    Behave/BDD
        (collection)         (REST API)        (parallel work)  (via REST API)

Tech Stack

  • Backend: Python 3, FastAPI, Uvicorn ASGI, PyYAML, Requests
  • GUI: Tkinter + ttk desktop application
  • Deploy: Docker Compose, Ubuntu 22.04, port 6767, /data volume for OAS files
  • Testing: Postman collection (included); REST control plane for BDD/CI integration
  • Domain: Automotive SOVD / OpenAPI contract testing

Usage (Quick Start)

docker compose build pyros
docker compose up pyros
# Optional GUI:
docker exec -it pyros bash
./scripts/start_pyros_gui.sh
  1. Connect GUI to http://127.0.0.1:6767
  2. Browse to OAS YAML in /data → click Load
  3. Endpoints appear in list → select one → Add Custom Response → set status + JSON
  4. Test with Postman or your application against port 6767

Don't wait for the backend — test with the spec today.