Base URL (local development): http://localhost:8000
Informational landing route. The service is API-only; the user interface is served separately by the frontend.
Response 200 OK
{
"service": "ModView API",
"version": "0.1.0",
"message": "This is the backend API. Open the frontend UI instead - ...",
"endpoints": ["POST /api/parse", "GET /api/health", "GET /docs"]
}Health check and Verible availability probe.
Response 200 OK
{ "status": "ok", "version": "0.1.0", "verible": true }version is the backend application version (see the repository
CHANGELOG). verible is false if the
verible-verilog-syntax binary cannot be found.
Parse one or more SystemVerilog files and return the extracted design.
Request — multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
files |
File[] | yes | .sv / .v source files |
top |
string | no | Top-module name hint; ranked first in top_candidates |
Limits: 20 000 files per request, 50 MB per file, 500 MB total. The high file count is what makes whole-directory uploads work; it is applied when the multipart body is read, so an over-large request is rejected before any file is written to disk.
Every 200 response has the same three keys:
| Key | Type | Description |
|---|---|---|
status |
"ok" | "partial" | "error" |
see below |
errors |
array | one entry per syntax error, possibly empty |
design |
object | the extracted design — present in all three states |
status |
Meaning |
|---|---|
ok |
Every file parsed; errors is empty |
partial |
Some files failed, but at least one module was extracted. The client can render the design and show the error list |
error |
Files failed and no module survived; there is nothing to render |
{
"status": "ok",
"errors": [],
"design": {
"modules": {
"cpu_top": {
"name": "cpu_top",
"ports": [
{ "name": "clk", "direction": "input", "width": 1 },
{ "name": "data_o", "direction": "output", "width": 32, "msb": 31, "lsb": 0 }
],
"parameters": { "WIDTH": "32" }
}
},
"top_candidates": ["cpu_top"],
"instances_by_parent": {
"cpu_top": [
{
"instance_name": "u_alu",
"module_name": "alu",
"parameters": {},
"connections": [
{ "port_name": "y", "signal": "alu_out" }
]
}
]
},
"interfaces": {},
"interface_instances_by_parent": {}
}
}width/msb/lsb are derived from constant packed ranges ([31:0]).
Parameterised ranges such as [WIDTH-1:0] fall back to width: 1.
A port declared as <interface>.<modport> <name> (e.g. pcie_avst_if.slave tx)
is reported with direction: "interface" plus the binding fields:
{
"name": "tx",
"direction": "interface",
"width": 1,
"interface_name": "pcie_avst_if",
"modport": "slave"
}A connection written as .bus(axi_bus.master) carries the binding on the
connection instead:
{
"port_name": "bus",
"signal": "axi_bus.master",
"interface_instance": "axi_bus",
"modport": "master"
}interface_instance / modport and interface_name / modport are omitted
when they do not apply, so a plain wire connection keeps the two-key shape
shown in the success example above.
Interface declarations appear under design.interfaces:
{
"interfaces": {
"axi_if": {
"name": "axi_if",
"signals": [{ "name": "cmd", "width": 8, "msb": 7, "lsb": 0 }],
"modports": {
"master": {
"name": "master",
"signals": [{ "name": "cmd", "direction": "output" }]
}
},
"parameters": {}
}
},
"interface_instances_by_parent": {
"cpu_top": [
{ "instance_name": "axi_bus", "interface_name": "axi_if", "parameters": {} }
]
}
}Some files failed; the modules that parsed are still returned.
{
"status": "partial",
"errors": [
{ "file": "broken.sv", "line": 42, "column": 8, "message": "syntax error (parse)" }
],
"design": { "modules": { "cpu_top": { "...": "..." } }, "...": "..." }
}Syntax errors are not HTTP failures. When nothing usable survives, the
status is error and design contains empty collections.
{
"status": "error",
"errors": [
{ "file": "cpu.sv", "line": 42, "column": 8, "message": "syntax error (parse)" }
],
"design": {
"modules": {},
"top_candidates": [],
"instances_by_parent": {},
"interfaces": {},
"interface_instances_by_parent": {}
}
}Returned for an empty request, an unsupported file extension, or an upload
that exceeds a size limit. The application's own errors use message:
{ "status": "error", "message": "unsupported file type: notes.txt" }A failure raised while the multipart body is being read is caught and
re-emitted in the same shape, prefixed multipart parse error: . A rejection
produced by the framework before the handler runs uses FastAPI's detail key
instead:
{ "detail": "..." }Clients should therefore read message first and fall back to detail; the
bundled frontend client does exactly that.
{ "error": "verible not found" }| Variable | Default | Purpose |
|---|---|---|
VERIBLE_BIN |
verible-verilog-syntax |
Path/name of the Verible binary |
SVMV_CORS_ORIGINS |
* |
Comma-separated allowed CORS origins |