Know every API
your code exposes.
Your OpenAPI file, gateway config, and traffic logs describe the API second-hand. The source code defines it. APIScout reads the source — locally, in VS Code — and turns it into an endpoint inventory you can review and export.
1 import { Router } from "express";
2 import { requireAuth } from "../middleware/auth";
3
4 const router = Router();
5
6 router.get("/payments", requireAuth,
7 async (req, res) => {
8 const payments = await db.payment.findMany({
9 where: { accountId: req.user.accountId }
10 });
11
12 return res.json({ data: payments });
13 }
14 );The problem
Your API surface is
emergent, not declared.
No file in your repository lists the endpoints your service exposes. That list is assembled at startup, from route registrations spread across modules and combined with prefixes applied wherever routers are mounted.
Everything that describes the result is secondary, and each decays differently:
- An OpenAPI file describes the API as it was understood when someone last edited it.
- A gateway config describes the routes that gateway manages — not the ones the service implements behind it.
- A traffic log describes the routes something called while you were watching.
All three are useful. None is authoritative. When they disagree with the code, the code wins — because the code is what is running. The gap between them has its own OWASP entry: improper inventory management.
Why this happens
Four changes that pass review.
None is a bug in the ordinary sense. Each changes what the service exposes in a way a line-oriented diff does not surface.
- app.use("/internal", adminRouter);
+ app.use("/v1/admin", adminRouter);A one-line change with no diff in any handler
Prefixes are applied where routers are mounted, files away from the handlers. No handler changed here — but every route in adminRouter moved from a prefix an ingress rule blocked to one it forwards. The reviewer sees one changed line.
app.mount("/legacy", legacy_wsgi_app)The routes a schema generator cannot see
springdoc and FastAPI's built-in schema read the framework's own routing table, so they cover routes declared the expected way and miss the rest. A mounted sub-application is opaque to that mechanism: reachable in production, absent from /openapi.json.
router.patch("/:id", requireAuth, updateProject);
router.delete("/:id", requireAuth, deleteProject);A destructive method added for symmetry
An agent asked to let users edit projects adds delete too, because the pattern looks incomplete without it. requireAuth proves the caller is authenticated — not that they own this project. That is the whole substance of a broken object-level authorization (BOLA) finding, in two lines.
app.use("/v1", legacyRouter); // "temporary"
app.use("/v2", currentRouter);The version that outlived its documentation
Traffic-based discovery only sees routes something called during capture, and nobody calls v1 much. Two years on the portal documents v2 only, security scopes tests from the portal, and v1 is still mounted — still running the authorization logic it shipped with.
How APIScout solves it
Read the definition,
not a description of it.
APIScout analyses backend source in your workspace and reconstructs the surface the way the framework does: it follows route registration through the modules that declare it, resolves mount-time prefixes, and reports a full path, method, and source location for every endpoint.
It runs where the code is
Discovery is local, on the workspace already open in VS Code. No environment to stand up, no service running, no traffic window, no upload. You can scan a branch that has never been deployed.
It keeps the link to the implementation
Every endpoint resolves to a file and line. When a row raises a question — who calls this, is it still needed — the answer is one jump away.
It produces a standard artifact
The export is OpenAPI 3.x. Deliberately unremarkable: it feeds documentation portals, client generators, contract tests, and security scanners with no proprietary format in between.
On the optional AI
APIScout can use local models to summarize endpoints and draft descriptions. Opt-in, on your machine. Discovery itself is deterministic analysis — the models add editorial convenience, not the inventory.
Supported frameworks
Will it read your backend?
APIScout ships a parser per framework, so it resolves routes the way that framework registers them rather than guessing from string matches.
FastAPI
PythonRecognized by fastapi in requirements.txt or pyproject.toml
Django
PythonRecognized by manage.py in project root
Flask
PythonRecognized by flask in requirements.txt or pyproject.toml
Express
Node.jsRecognized by express in package.json dependencies
NestJS
TypeScriptRecognized by @nestjs/core in package.json dependencies
Also an input
An existing OpenAPI file in the workspace is parsed alongside the source, so you can compare what a checked-in spec claims against what the code registers.
Not yet covered
Spring, Rails, Laravel, and Go have no parser today. A scan of those projects returns whatever the OpenAPI parser finds, not a source-derived route inventory.
Technical workflow
From checkout to exported spec.
Install and open
Install from the VS Code Marketplace and open the backend repository. No configuration, no annotations, no dependency added to the application.
Scan the source tree
APIScout walks the workspace and resolves route registrations into full paths with their methods, grouped by module.
Review and trace
Filter by method or path. Open an endpoint to see its source location, then jump into the file to check middleware and handler logic.
Export and hand off
Export OpenAPI YAML or JSON. Commit it as a baseline, feed a documentation portal, or import it into ApyGuard as test scope.
Inside the extension
See the API you
actually expose.
Search by path or method, inspect source-backed details, and jump from the inventory to the implementation. This sample is interactive — try filtering it.
Lists account-scoped payment records and maps the route back to the source file instantly.
Parameter and auth context stay attached to the route
APIScout keeps route details grounded in implementation context so OpenAPI cleanup starts from real code.
Move from code discovery to schema export
The extension helps teams turn route inventory into an OpenAPI baseline instead of manually reconstructing paths from scattered files.
Three ways to build an inventory
Source, traffic, or specification.
These are competing evidence types more than competing products. Knowing which question each one answers is most of the skill.
| Question | Source analysis | Traffic capture | Spec-first |
|---|---|---|---|
| Finds a route nobody has called | Yes — registration is in the code | No — coverage equals observed traffic | Only if someone documented it |
| Reflects code merged five minutes ago | Yes — scans the working tree | After deploy, then after traffic | Only after a manual edit |
| Requires a running service | No | Yes — needs a deployed environment | No |
| Proves authorization actually holds | No — structure, not behavior | Partially — observed responses | No — describes intent |
Source analysis gives the best coverage of what exists, traffic the best evidence of what is used, a specification the clearest statement of intent. Mature API programs keep all three and reconcile the differences deliberately.
What changes for each role
Visibility pays before it becomes a requirement.
For developers
You stop reconstructing routing graphs by hand. Onboarding starts with a list of what a service exposes. Before opening a pull request, you can check what your branch made reachable — including routes an agent added while you reviewed something else.
For teams and architects
The API surface becomes a reviewable artifact instead of tribal knowledge. Migrations start from a route baseline rather than assumptions, and committed exports turn contract change into something you can diff between releases.
For security and DevSecOps
Test scope stops depending on whichever spec development could find. Undocumented, internal, and legacy routes enter the inventory on equal footing. Because discovery runs pre-deploy, a new privileged endpoint can be assessed before it becomes production behavior.
Export and test
Turn visibility into
a usable spec.
Once you know the real API surface, export OpenAPI YAML or JSON from the implementation. Use it for documentation, contract work, or API security testing in ApyGuard.
1. Discover what is exposed
Scan backend source locally to find routes that traffic capture and stale specs can miss.
2. Trace every route to code
Filter by method and path, then jump to the file that defines the endpoint and its context.
3. Export a usable OpenAPI baseline
Generate YAML or JSON from the implementation for documentation, testing, and security workflows.
openapi: 3.1.0
info:
title: payments-api
version: 1.0.0
paths:
/payments:
get:
summary: List payments
security:
- bearerAuth: []
responses:
"200":
description: Payment list
post:
summary: Create payment
responses:
"201":
description: Payment created
/payments/{id}:
get:
summary: Get payment by id
parameters:
- in: path
name: id
required: true
schema:
type: stringIn practice
Make API visibility a normal step.
Check the API surface on pull requests that touch route registration.
Not on every pull request, and not from the diff alone.
Commit reviewed exports as release artifacts.
The diff between two releases is the shortest description of contract change.
Scope security tests from the export, with disposable identities.
Not from the developer portal — that describes the product, not the service.
Give every intentionally undocumented route an owner.
Undocumented is a legitimate choice; unowned is not.
Run discovery on first checkout of an unfamiliar service.
A route list explains it faster than a README written for an older version.
Treat a traffic inventory as complete for its capture window only.
And a green CI run as evidence that features work, not that exposure is intended.
FAQ
Questions engineers ask before installing.
How is this different from swagger-autogen, springdoc, or FastAPI's built-in schema?
Those run inside your application and read the framework's routing table, so they only see routes registered the expected way. APIScout analyses source without executing anything. If you already publish a generated spec, this is a good way to check what it missed.
Why not just use traffic-based API discovery?
Traffic tells you what was called; source tells you what can be called. Most teams need both — which is why ApyGuard offers traffic discovery alongside APIScout, not instead of it.
Does my source code leave my machine?
No. Scanning is local to the workspace open in VS Code, and the optional AI runs against local models. Discovery and export need no account and no network call.
Is the generated OpenAPI file production-ready documentation?
It is a source-backed baseline. Paths and methods come from the implementation and are reliable; descriptions and examples are not something code can supply. Generate the structure, then add the meaning.
What does it cost?
Free, from the Visual Studio Code Marketplace, and it works without an ApyGuard account.
Can it detect vulnerabilities?
No. APIScout reports structure. The most serious API flaws — broken object- and function-level authorization — are runtime properties of a specific identity, and proving them means sending requests as one user and seeing what another user's data does in the response.
How often should the inventory be regenerated?
When routing changes, not on a calendar. Adding a router, moving a mount point, or changing an authentication boundary warrants a new one.
When APIScout is not enough
Discovery is the first step,
not the whole job.
Static discovery reports structure. It does not execute your application, and there are questions it cannot answer.
It cannot confirm that a deployment mounts the routes a branch declares, or that an ingress or service mesh has not added paths of its own. And it cannot tell you whether authorization holds — whether GET /invoices/:id returns another tenant's invoice for a valid token belonging to someone else.
That last category is where the most damaging API flaws live — broken object-level authorization and broken function-level authorization. Proving them requires real requests under controlled identities. No amount of source analysis substitutes for it.
How ApyGuard extends the workflow
Test the surface you discovered.
ApyGuard takes the OpenAPI file APIScout generated and uses it as test scope, exercising each endpoint under controlled identities to check for OWASP API Top 10 conditions — authorization failures, mass assignment, injection, misconfiguration — against development, staging, production, or private-network APIs.
The split is clean: APIScout answers what is exposed, ApyGuard answers whether that exposure is safe.
Source code → APIScout → OpenAPI → ApyGuard → Automated security testing
Test this API in ApyGuardAPIScout for VS Code
Find out what your
service actually exposes.
Free and local-first. Install it, open a backend repository, and read the endpoint inventory before your next release decides it for you.