Skip to main content

Static-analysis CLI that detects mismatches between frontend API calls and backend endpoints.

Project description

๐Ÿ‘ป API Ghost Hunter

Python Support CI status License: MIT

A static-analysis CLI tool that scans full-stack codebases, detects API calls made by the frontend, detects API endpoints exposed by the backend, compares them, and identifies broken paths, potentially unused endpoints, and method mismatches. Supports both local directories and remote GitHub repositories.


The Problem

In modern full-stack web applications, frontends and backends evolve at different speeds. Over time, APIs get renamed, endpoints are deleted, and query/path parameter requirements shift. This leaves:

  • Ghost Calls: Frontend code calling endpoints that no longer exist, causing 404 Not Found errors in production.
  • Ghost Endpoints: Backend controllers exposing dead code that is no longer consumed by the frontend, adding maintenance overhead.

API Ghost Hunter solves this problem by statically analyzing your repository without requiring a running server, dynamic agents, or complicated integration test suites.


Key Features

  • Static Analysis: Scans source code directly. Safe, fast, and does not require running your application or database.
  • Remote Repository Scanning: Directly scan remote GitHub, GitLab, or Bitbucket repositories by passing the Git URL.
  • Frontend Support: Automatically detects JS/TS fetch() calls, direct and config-style axios requests, axios.create() instances with custom baseURL resolutions, Angular HttpClient, and jQuery AJAX shorthand/config calls.
  • Backend Support: Full detection of Spring Boot, Express.js, Flask, FastAPI, Django & DRF, NestJS, Go (Gin, Echo, Chi, net/http), Ruby on Rails, and OpenAPI/Swagger specs.
  • Dynamic Route Matching: Correctly handles and matches path parameters such as /api/users/123 with backend mappings like /api/users/{id}.
  • Method Mismatch Detection: Reports when paths match but HTTP methods differ (e.g., frontend requests GET but backend expects POST).
  • Intelligent Recommendations: Suggests similar matching endpoints using deterministic similarity algorithms (difflib, segment edit distance) with a confidence score.
  • Environment Variable Resolution: Reads .env, .env.local, and .env.development files to resolve runtime URL strings used in frontends.
  • CI/CD Integration: Supports custom exit codes (--fail-on-broken), ignore files, JSON/SARIF reporting formats, and summary-only output.

Installation

You can install API Ghost Hunter from source or via pip (once published):

# Clone the repository
git clone https://github.com/api-ghost-hunter/api-ghost-hunter.git
cd api-ghost-hunter

# Install in editable mode
pip install -e .

Quick-Start Example

Scan your local workspace from the command line:

api-ghost-hunter scan .

Scan a remote GitHub repository directly:

api-ghost-hunter scan https://github.com/owner/fullstack-app

Scan separate remote frontend and backend repositories:

api-ghost-hunter scan . --frontend https://github.com/owner/frontend --backend https://github.com/owner/backend

Generate a SARIF report file for GitHub Code Scanning integration:

api-ghost-hunter scan . --format sarif -o results.sarif

Fail the CI build if there are broken calls with minimal output:

api-ghost-hunter scan . --quiet --fail-on-broken

Create a template configuration file:

api-ghost-hunter init

Display the complete interactive guide and tech reference:

api-ghost-hunter guide

Example Terminal Output

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                                                                              โ”‚
โ”‚                                                                              โ”‚
โ”‚   โ–ˆโ–€โ–€โ–ˆ โ–ˆโ–€โ–€โ–ˆ โ–€โ–ˆโ–€   โ–ˆโ–€โ–€โ–ˆ โ–ˆ  โ–ˆ โ–ˆโ–€โ–€โ–ˆ โ–ˆโ–€โ–€โ–€ โ–€โ–€โ–ˆโ–€โ–€   โ–ˆ  โ–ˆ โ–ˆ  โ–ˆ โ–ˆโ–€โ–€โ–ˆ โ–€โ–€โ–ˆโ–€โ–€ โ–ˆโ–€โ–€ โ–ˆโ–€โ–€โ–ˆ  โ”‚
โ”‚   โ–ˆโ–„โ–„โ–ˆ โ–ˆโ–„โ–„โ–ˆ  โ–ˆ    โ–ˆ โ–„โ–„ โ–ˆโ–€โ–€โ–ˆ โ–ˆ  โ–ˆ โ–€โ–€โ–€โ–ˆ   โ–ˆ     โ–ˆโ–€โ–€โ–ˆ โ–ˆ  โ–ˆ โ–ˆ  โ–ˆ   โ–ˆ   โ–ˆโ–€โ–€ โ–ˆโ–„โ–„โ–€  โ”‚
โ”‚   โ–€  โ–€ โ–€    โ–„โ–ˆโ–„   โ–€โ–„โ–„โ–ˆ โ–€  โ–€ โ–€  โ–€ โ–ˆโ–„โ–„โ–ˆ   โ–€     โ–€  โ–€ โ–€โ–€โ–€โ–€ โ–€  โ–€   โ–€   โ–€โ–€โ–€ โ–€ โ–€โ–€  โ”‚
โ”‚                                                                              โ”‚
โ”‚    ยป Static API Contract & Drift Analyzer ยซ  v0.1.0                          โ”‚
โ”‚                                                                              โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

โ•ญโ”€ ๐Ÿ“Š Scan Metrics โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚   Frontend API Calls Scanned      13                                         โ”‚
โ”‚   Backend Endpoints Scanned       64                                         โ”‚
โ”‚   API Contract Matches            10                                         โ”‚
โ”‚   Broken Calls (Ghost APIs)        2                                         โ”‚
โ”‚   HTTP Method Mismatches           0                                         โ”‚
โ”‚   Potentially Unused Endpoints    55                                         โ”‚
โ”‚   Unresolved Dynamic Calls         1                                         โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

๐Ÿ”ด GHOST APIS DETECTED (BROKEN CONTRACTS)
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ CRITICAL: Frontend tries to call non-existent endpoint:                      โ”‚
โ”‚   POST /api/posts                                                            โ”‚
โ”‚                                                                              โ”‚
โ”‚   Location:  frontend/src/api.js:17 (axios framework)                        โ”‚
โ”‚       ยป POST /api/users (63%)                                                โ”‚
โ”‚       ยป POST /api/users (63%)                                                โ”‚
โ”‚       ยป POST /api/users (63%)                                                โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ CRITICAL: Frontend tries to call non-existent endpoint:                      โ”‚
โ”‚   GET /api/orders                                                            โ”‚
โ”‚                                                                              โ”‚
โ”‚   Location:  frontend/src/api.js:40 (axios framework)                        โ”‚
โ”‚       ยป GET /api/users (66%)                                                 โ”‚
โ”‚       ยป GET /api/users (66%)                                                 โ”‚
โ”‚       ยป GET /api/users (66%)                                                 โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

Detailed Technical Architecture & Logic

1. Static Parsing Engine

A. Frontend API Call Detection

The frontend parser scans JS/TS/TSX files for API calls. Rather than using simplistic global regexes, it uses a multi-stage parser:

  1. Comment Stripping: The parser strips block (/* ... */) and line (// ...) comments while replacing characters with whitespace/newlines. This preserves the exact code positions and line numbers for warnings and errors.
  2. Fetch Extraction: Resolves calls to the standard fetch() API. If a method option is not explicitly found, it defaults to GET.
  3. Axios Extraction: Resolves direct axios methods (axios.get, axios.post, etc.), standard axios configuration parameters (axios({ method: "...", url: "..." })), and custom client instances initialized via axios.create({ baseURL: "/api" }). The parser tracks multiple instances and automatically prepends their configured baseURL values to relative target endpoints.
  4. Angular HttpClient: Extracts constructor-injected HttpClient calls (e.g. this.http.get<Item[]>('/api/items') or this.http.request('POST', ...)) in TypeScript components.
  5. jQuery AJAX: Resolves shorthand jQuery calls ($.get, $.post, $.getJSON) and config objects ($.ajax({ url: '/api', method: 'PUT' })).
  6. Template Literals: Translates template string placeholders (e.g. `/api/users/${userId}`) into generic tokens (e.g. /api/users/{param}) for route matching.
  7. Environment Variables: Resolves process.env.* and import.meta.env.* references by matching them with keys found in local .env, .env.local, and .env.development files.
  8. Unresolved Variable Detection: If the endpoint URL is composed of an unresolvable variable or custom function call (e.g., fetch(apiUrl)), it logs the expression as UNRESOLVED to prevent false positive broken alerts.

B. Backend Endpoint Detection

The backend parser extracts exposed controller mappings:

  1. Spring Boot (Java/Kotlin): Scans @RequestMapping("/prefix") annotations declared at the controller class level.
  2. Express.js (Node.js): Resolves router instances, app.get/post, chaining, and mount paths using .use().
  3. Flask (Python): Parses @app.route(), methods= arrays, Blueprint routing, and <converter> variables.
  4. FastAPI (Python): Extracts path parameters, async/sync routes, and APIRouter sub-routers.
  5. Django (Python): Resolves urlpatterns (path(), re_path()), DRF Routers (DefaultRouter, SimpleRouter), ViewSets, and @api_view decorated functions.
  6. NestJS (TypeScript): Detects controller decorators, HTTP method mappings, and router prefix structures.
  7. Go (Go): Resolves Gin (r.GET), Echo (e.POST), Chi (r.Get), net/http (http.HandleFunc), and route groups.
  8. Ruby on Rails (Ruby): Parses routes.rb for standard verbs, resource macros (resources :users), scopes, namespaces, and root paths.
  9. OpenAPI / Swagger Specs: Parses API schemas (openapi.yaml/json, swagger.yaml/json), extracting URLs, basePath configuration, servers block, and HTTP methods.

C. Smart Parser Selection

To ensure fast execution in large codebases, the scanner does not run all backend parsers on every file. It matches file extensions to select relevant parsers (e.g. .py files only invoke Django/Flask/FastAPI parsers, .go only invokes Go parser, etc.), significantly reducing processing time.


2. Route Normalization

Before matching, paths are normalized to guarantee comparison consistency:

  • Query Stripping: Removes query parameters (e.g. /api/users?page=1 becomes /api/users).
  • Hash/Fragment Stripping: Removes hash segments (e.g. /api/users#profile becomes /api/users).
  • Slash Consolidation: Collapses consecutive slashes (e.g. /api//users/ becomes /api/users).
  • Trailing Slash Removal: Strips trailing slashes (e.g. /api/users/ becomes /api/users).
  • Spring Parameter Regex Normalization: Cleans up path parameter validation regexes (e.g., /api/users/{id:\d+} becomes /api/users/{id}).
  • Case Insensitivity: Converts paths to lowercase.

3. Matching & Similarity Engine

The engine resolves matching in five sequential passes to prevent false reports:

Pass Match Category Details
1 Exact Match Matches exact normalized path and HTTP method (e.g. frontend GET /api/users vs backend GET /api/users).
2 Dynamic Route Match Matches path parameters and dynamic variables (e.g. frontend /api/users/123 or /api/users/{param} vs backend /api/users/{id}).
3 Method Mismatch Matches the endpoint path, but the HTTP method differs (e.g., frontend sends GET /api/orders but backend accepts POST /api/orders).
4 Similar suggestions If there is no match, computes similarity scores between the broken path and exposed backend endpoints using token segment comparison combined with edit-distance ratios.
5 Potentially Unused Any backend endpoints that remain unmatched by any frontend call are flagged as "Potentially Unused".

Supported Technologies

Layer Library / Framework Support Features
Frontend JS/TS fetch() Direct URLs, Multi-line options objects, Method extraction, Template literals
Frontend Axios (axios) Direct calls, Config-style calls, axios.create() instances, baseURL resolutions
Frontend Angular HttpClient http.get<T>(), http.post(), etc., http.request(), constructor injection resolution
Frontend jQuery AJAX $.get(), $.post(), $.getJSON(), $.ajax() configuration parameters
Backend Spring Boot @RequestMapping, @GetMapping, @PostMapping, etc., class-level + method-level path combination, array paths
Backend Express.js (Node.js) app.get(), app.post(), app.put(), app.patch(), app.delete(), app.all(), app.route(), express.Router(), app.use() mounting, :param path params
Backend Flask (Python) @app.route(), @app.get(), @app.post(), methods array, converters, Blueprints
Backend FastAPI (Python) @app.get(), @app.post(), @app.api_route(), APIRouter, {param}, {param:type}, async routes
Backend Django (Python) path(), re_path(), default and simple DRF routers, DRF ViewSets, @api_view decorators
Backend NestJS (TypeScript) @Controller() with prefix, @Get(), @Post(), @Put(), @Patch(), @Delete(), @All(), :param path params
Backend Go Router Gin (r.GET), Echo (e.POST), Chi (r.Get), net/http (http.HandleFunc), group prefix resolution
Backend Ruby on Rails get/post/put/delete, resources macro with only/except filters, namespace, scope blocks
Specs OpenAPI / Swagger YAML & JSON format support, servers configuration blocks, basePath definitions

Configuration

You can configure options in a project-root configuration file called ghosthunter.yaml:

frontend:
  paths:
    - frontend/src

backend:
  paths:
    - backend/src

ignore:
  - "/actuator/**"
  - "/api/internal/**"

exclude:
  - "**/*.test.ts"
  - "**/generated/**"

Configuration Fields

  • frontend.paths: A list of paths to look for frontend files in. Defaults to root scan directory if omitted.
  • backend.paths: A list of paths to look for backend files in. Defaults to root scan directory if omitted.
  • ignore: API URL path patterns (glob-style) to ignore from matching. If an API call or endpoint starts with or matches a prefix, it is skipped.
  • exclude: File exclusion patterns (glob-style) to skip scanning (e.g. test files, mock databases).

CLI arguments take precedence over any settings specified in ghosthunter.yaml.


CLI Reference

api-ghost-hunter scan

api-ghost-hunter scan [DIRECTORY] [OPTIONS]

Arguments

  • DIRECTORY: The root workspace directory or remote Git repository URL to scan. Defaults to ..

Options

  • --frontend: Override frontend folder paths or remote Git URL.
  • --backend: Override backend folder paths or remote Git URL.
  • --format: Output format: terminal (polished panels), json, or sarif.
  • --output, -o: File path to write the JSON/SARIF report to.
  • --quiet, -q: Print only a one-line summary. Ideal for CI/CD usage.
  • --fail-on-broken: If set, returns exit code 1 when any broken frontend call is detected.
  • --ignore: Add API patterns to ignore during scan.
  • --verbose: Show detailed debug logs and warnings.

api-ghost-hunter init

api-ghost-hunter init [DIRECTORY] [OPTIONS]

Generates a starter ghosthunter.yaml configuration file.

api-ghost-hunter guide

api-ghost-hunter guide

Displays complete user manual and framework documentation directly in the terminal.

Exit Codes

  • 0: Scan completed cleanly with no broken calls.
  • 1: Broken frontend calls (or method mismatches) were detected (only triggers if --fail-on-broken is enabled).
  • 2: Configuration, parsing, or command execution error.

CI/CD Usage

GitHub Actions (SARIF Integration)

Add this step to your GitHub Actions workflow file to run checks and upload results:

- name: Run API Ghost Hunter Scan
  run: |
    pip install api-ghost-hunter
    api-ghost-hunter scan . --format sarif --output results.sarif

- name: Upload SARIF report
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: results.sarif

Contributing

Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.


License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api_ghost_hunter-0.1.0.tar.gz (61.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

api_ghost_hunter-0.1.0-py3-none-any.whl (70.4 kB view details)

Uploaded Python 3

File details

Details for the file api_ghost_hunter-0.1.0.tar.gz.

File metadata

  • Download URL: api_ghost_hunter-0.1.0.tar.gz
  • Upload date:
  • Size: 61.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for api_ghost_hunter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 a6d8d7c971b9117a00576f6292d8dfa6137dfea56791d30ef854db092d59284e
MD5 757b6c35632ba185bc220e3810f647ca
BLAKE2b-256 91a3d6e87a98138bdf486375f1f70f8d892035eb237953b10c9e58fc630c304d

See more details on using hashes here.

File details

Details for the file api_ghost_hunter-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for api_ghost_hunter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 adacb515bf5d3532936b98d97a69d5ecf44cf682249f31e9a217c3a8c1a12c5b
MD5 69aa9404a60ad3bc69a29977e90f5fa8
BLAKE2b-256 d917d1cc088c7460517745852606eba3de2faea55a6a5da918e2a4df6da14bec

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page