Automatically extract REST API definitions from source code and generate OpenAPI specifications.
- Automatic Framework Detection: Detects web frameworks in your codebase
- Multi-Language Support: Python, JavaScript/TypeScript, Java, C#, and Go
- OpenAPI 3.1 Output: Generates standard OpenAPI specifications in JSON or YAML
- Tree-sitter Based: Uses Tree-sitter Query Language for accurate AST parsing
- Production Validated: Tested against real-world projects including Cal.com, Dub, Spring Boot RealWorld, and more
- Multiple Deployment Modes: CLI, HTTP Server, Docker, Kubernetes, AWS Lambda
API Extractor uses static analysis (Tree-sitter AST parsing) rather than LLMs. Here's why this approach is superior for API extraction:
| Aspect | Static Analysis (This Tool) | LLM-Based Extraction |
|---|---|---|
| Accuracy | 99.9% - Deterministic pattern matching | 70-90% - Probabilistic, prone to hallucination |
| False Negatives | Near zero - Catches all syntactically valid routes | 10-30% - Misses uncommon patterns or complex routing |
| False Positives | Extremely rare - Only matches actual route definitions | 5-15% - May hallucinate non-existent endpoints |
| Cost | $0 per extraction | $0.01-$0.50 per project (varies by size) |
| Speed | 100-1000ms per project | 5-30 seconds per project |
| Consistency | 100% - Same input = same output | Variable - Different runs may yield different results |
| Privacy | Local processing, no data leaves your infrastructure | Code must be sent to third-party API |
| Complex Patterns | Handles dynamic routing, router composition, inheritance | Struggles with indirection and metaprogramming |
| Schema Extraction | Precise type inference from decorators/annotations | Best-effort approximation from context |
Determinism: Route definitions follow strict syntactic patterns. Static analysis exploits this structure for perfect accuracy.
No Hallucinations: LLMs can invent endpoints that don't exist, especially when "inferring" from similar patterns. Static analysis only reports what's actually defined in code.
Performance at Scale: Processing 100 microservices:
- Static: ~10 seconds total, fully parallelizable
- LLM: 10+ minutes, rate-limited by API calls
Cost at Scale:
- Static: $0 infrastructure cost (CPU only)
- LLM: $5-50 per 100 projects, recurring on every run
Privacy & Compliance: Many organizations cannot send source code to external APIs. Static analysis runs entirely offline.
Edge Cases: Static analysis handles known patterns like router composition and inheritance, but struggles with:
- Custom decorators not in pattern database
- Novel framework variants or forks
- Non-standard routing mechanisms
- Domain-specific API frameworks
This is where LLMs shine: They generalize to patterns they've never seen before. An LLM can infer "this looks like a route definition" even if it uses custom decorators or unconventional syntax.
The Trade-off:
- Static Analysis: Rigid but precise - 100% accuracy on known patterns, 0% on unknown patterns
- LLMs: Flexible but noisy - 80% accuracy on everything, including novel patterns
Optimal Approach: Hybrid system using static analysis as primary with LLM fallback for unmatched code. This combines precision (static) with adaptability (LLM).
API Extractor focuses on accurate extraction from known patterns; LLMs excel at handling novel patterns and semantic understanding.
pip install -r requirements.txt
pip install -e .api-extractor extract /path/to/projectapi-extractor extract /path/to/project --output api-spec.yaml --format yamlAPI Extractor supports 10 major web frameworks across 5 languages:
| Language | Frameworks | Documentation |
|---|---|---|
| Python | FastAPI, Flask, Django REST | → Python Guide |
| JavaScript/TypeScript | Express, NestJS, Fastify, Next.js | → JavaScript Guide |
| Java | Spring Boot | → Java Guide |
| C# | ASP.NET Core | → C# Guide |
| Go | Gin | → Go Guide |
Next.js:
api-extractor extract /path/to/nextjs-app --output nextjs-api.json
# Detects: app/api/ or pages/api/ directoriesSpring Boot:
api-extractor extract /path/to/spring-boot-app --output spring-api.yaml --format yaml
# Detects: pom.xml, build.gradle, @RestController annotationsFastAPI:
api-extractor extract /path/to/fastapi-app --output fastapi-spec.json
# Detects: FastAPI decorators and type hintsAPI Extractor can run in three modes:
Command-line tool for batch extraction from local codebases.
# Basic usage
api-extractor extract /path/to/project
# With custom output and metadata
api-extractor extract . \
--output my-api.yaml \
--format yaml \
--title "My API" \
--version "2.0.0" \
--verboseCLI Options:
| Option | Short | Type | Default | Description |
|---|---|---|---|---|
--output |
-o |
path | openapi.json |
Output file path |
--format |
-f |
choice | json |
Output format (json or yaml) |
--verbose |
-v |
flag | false | Show detailed extraction progress |
--title |
- | string | Extracted API |
API title in OpenAPI spec |
--version |
- | string | 1.0.0 |
API version in OpenAPI spec |
Run as an HTTP API server for on-demand code analysis. Ideal for sidecar deployment in containerized environments.
# Start server
api-extractor serve
# Custom configuration
api-extractor serve --host 127.0.0.1 --port 9000Use Cases:
- Runtime API discovery
- CI/CD integration
- API gateway integration
- Service mesh integration
- Documentation automation
→ See HTTP Server Documentation
Deploy as a serverless function with S3 Files filesystem mount for on-demand extraction.
cd deployment/lambda
./setup_vpc.sh
./setup_s3_files.sh
./build_lambda.sh
./deploy_lambda.sh| Deployment | Use Case | Documentation |
|---|---|---|
| CLI | Local development, CI/CD pipelines | Built-in |
| Docker | Containerized environments | → Docker Guide |
| HTTP Server | Sidecar pattern, service mesh | → HTTP Server Guide |
| Kubernetes | Production orchestration | → Kubernetes Guide |
| AWS Lambda | Serverless, on-demand extraction | → Lambda Guide |
Given a FastAPI application:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"id": user_id}Running:
api-extractor extract . --verboseGenerates:
{
"openapi": "3.1.0",
"info": {
"title": "Extracted API",
"version": "1.0.0"
},
"paths": {
"/users/{user_id}": {
"get": {
"tags": ["fastapi"],
"parameters": [
{
"name": "user_id",
"in": "path",
"required": true,
"schema": {"type": "integer"}
}
],
"responses": {
"200": {"description": "Success"}
}
}
}
}
}API Extractor uses Tree-sitter Query Language for pattern matching across multiple languages:
graph TB
root["API Extractor Core"]
subgraph python["Python Extractors"]
fastapi["FastAPI"]
flask["Flask"]
django["Django REST Framework"]
fastapi --> pydantic["Pydantic<br/>(built-in)"]
flask --> marshmallow["Marshmallow"]
flask --> flask_smorest["Flask-RESTX<br/>flask-smorest"]
django --> drf_serializers["DRF Serializers"]
end
subgraph javascript["JavaScript/TypeScript Extractors"]
express["Express"]
nestjs["NestJS"]
fastify_js["Fastify"]
nextjs["Next.js<br/>(App & Pages Router)"]
express --> joi["Joi"]
express --> zod["Zod"]
express --> ajv["AJV"]
nestjs --> class_validator["class-validator<br/>class-transformer"]
nestjs --> ts_types["TypeScript Types"]
nextjs --> nextjs_zod["Zod"]
fastify_js --> fastify_schema["JSON Schema"]
fastify_js --> typebox["TypeBox"]
fastify_js --> fastify_ajv["AJV"]
end
subgraph java["Java Extractors"]
spring["Spring Boot"]
spring --> hibernate["Hibernate Validator<br/>(JSR-380)"]
spring --> jackson["Jackson Annotations"]
end
subgraph csharp["C# Extractors"]
aspnet["ASP.NET Core"]
aspnet --> data_annotations["Data Annotations"]
aspnet --> fluent["FluentValidation"]
end
subgraph golang["Go Extractors"]
gin["Gin"]
gin --> go_validator["go-playground/validator"]
gin --> go_structs["Go Struct Tags"]
end
root --> python
root --> javascript
root --> java
root --> csharp
root --> golang
style root fill:#4caf50,stroke:#1b5e20,color:#fff,stroke-width:3px
style python fill:#3776ab,stroke:#1565c0,color:#fff
style javascript fill:#f7df1e,stroke:#f9a825
style java fill:#007396,stroke:#004d6d,color:#fff
style csharp fill:#9b4f96,stroke:#6a1b66,color:#fff
style golang fill:#00add8,stroke:#007d9c,color:#fff
style fastapi fill:#009688,stroke:#004d40,color:#fff
style flask fill:#000,stroke:#333,color:#fff
style django fill:#0c4b33,stroke:#062a1e,color:#fff
style express fill:#444,stroke:#222,color:#fff
style nestjs fill:#e0234e,stroke:#a01832,color:#fff
style nextjs fill:#000,stroke:#333,color:#fff
style spring fill:#6db33f,stroke:#4a7c2c,color:#fff
style aspnet fill:#512bd4,stroke:#3a1f9c,color:#fff
style gin fill:#00add8,stroke:#007d9c,color:#fff
Legend:
- Framework extractors (darker boxes) - Parse route definitions and controller structures
- Validation libraries (lighter boxes) - Extract request/response schemas and validation rules
- Multi-validation support - Express supports Joi, Zod, and AJV simultaneously
- Parse source code into AST: Tree-sitter parses files into abstract syntax trees
- Query for patterns: Framework-specific queries match route definitions
- Extract route information: HTTP methods, paths, parameters, and handlers
- Normalize to OpenAPI: Routes are converted to OpenAPI 3.1 format
pytest tests/ -vpytest tests/ -v --cov=api_extractor --cov-report=term-missing- Total Tests: 161 (158 passing, 3 known issues)
- Coverage: 82% overall
Contributions are welcome! To add support for a new framework:
- Create a new extractor extending
BaseExtractor - Write Tree-sitter queries to match framework patterns
- Add test fixtures and unit tests
- Validate against real-world projects
- Update documentation
See existing extractors in api_extractor/extractors/ for reference.
-
Framework Guides: docs/frameworks/
- Python - FastAPI, Flask, Django REST
- JavaScript/TypeScript - Express, NestJS, Fastify, Next.js
- Java - Spring Boot
- C# - ASP.NET Core
- Go - Gin
-
Deployment Guides: docs/deployment/
-
Additional Guides: docs/guides/
- Ensure you're running the extractor on the correct directory (source code, not build artifacts)
- Check that the framework is correctly detected with
--verboseflag - Verify that route decorators/annotations are using standard patterns
- For Express: Ensure routers are defined and mounted in the same file
- For Flask: Check that Blueprint mounting (
app.register_blueprint()) is present - For NestJS: Verify controllers are decorated with
@Controller()and methods with HTTP decorators - For Spring Boot: Ensure controllers use
@RestControlleror@Controllerannotations
Check that parameter syntax matches the framework:
- Express/NestJS/Fastify:
:paramName - Flask:
<type:paramName>or<paramName> - FastAPI:
{paramName} - Spring Boot/ASP.NET Core:
{paramName} - Gin:
:paramName
- For large codebases, consider extracting from specific subdirectories
- Manually exclude
node_modules,venv,target/,bin/, etc.
MIT License