# List Every API Endpoint in an Express App

An agent follows Express router mounts and auth middleware, probes a disposable local server, and returns a route and parameter inventory.

[Run this on Rush](https://cloud.getrush.ai/run/api-endpoint-inventory/express/), in a Project that has your repository.

## What the agent does

The agent reconstructs the router tree from the application entry point. In gothinkster/node-express-realworld-example-app, `src/main.ts:16` mounts `routes`, and `src/app/routes/routes.ts:13` mounts the composed router at `/api`. That file combines tags, articles, profiles and authentication controllers. The inventory joins those mount paths to the paths in each controller. It separately identifies `src/main.ts:21-23`, where the root route returns a status response, rather than pretending every HTTP handler belongs under the API prefix.

It records the actual middleware chain in declaration order. `src/app/routes/auth/auth.ts:15-25` defines `required` JWT authentication and `optional` authentication with `credentialsRequired: false`. The token parser accepts either `Token` or `Bearer` as the header scheme. `article.controller.ts:45-48` protects `/articles/feed`, while lines 87-90 use optional authentication on `/articles/:slug`. The agent preserves their order so the literal feed route cannot be confused with a slug. Comments become hints to verify, not the source of truth for the final method and path.

Parameters come from the code that consumes them. The article list passes `req.query` into its service, creation reads `req.body.article`, comment creation reads `req.body.comment.body` and comment deletion converts the route's id to a number. The agent follows those services for required fields and ownership checks, then classifies anonymous reads, authenticated mutations and public account creation separately. In `auth.controller.ts:14` registration has no auth middleware, while `auth.controller.ts:45` applies `auth.required` to the current-user endpoint. Those are different intended behaviors.

For runtime checks, it reads `package.json`, `package-lock.json` and `src/prisma/schema.prisma`, which declares PostgreSQL and `DATABASE_URL`. The README provides `npx prisma generate`, `npx prisma migrate deploy` and `npx nx serve api`; `package.json:6-8` exposes Nx start, build and test scripts. The agent prepares only sandbox-owned database state, sets a fresh local JWT secret and checks credential-free requests against that local server. It records actual statuses and response shapes, including the `UnauthorizedError` handling in `src/main.ts:34-38`. An unavailable database becomes a verification limit.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Inventory the attached Express app in endpoints.md. Follow app.use and Router mounts, route declaration order, auth middleware and handlers through to parameter validation and ownership checks. List every method/path, handler file:line, path/query/body fields and expected authentication. Use the lockfile and documented setup to start a disposable local instance with a sandbox-owned database and fresh local secrets. Probe routes without credentials where safe, recording status and response type. Distinguish public reads and registration from unexpectedly accessible protected operations. Record all unverified routes. Do not contact production, edit source, push or open a PR.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

`endpoints.md` shows the fully composed URL next to its controller registration, handler and middleware requirements. Parameter notes retain nested JSON envelopes such as `article` and `comment`, which a generic route dump would omit. The report distinguishes missing credentials from invalid credentials and distinguishes authentication from the service's ownership rules. A source-only inference carries that label rather than borrowing confidence from an unrelated passing request.

Before accepting the inventory, a reviewer checks literal-versus-parameter route ordering, public RealWorld reads, the protected current-user and feed routes, and whether local seeded records exercise meaningful paths. The artifact includes reproduction commands without secret values and an appendix for setup failures. Read it from the session's artifact list and inspect the transcript for the commands behind any claimed HTTP observation; no upstream pull request is part of this job.

## Run it on every router change

Your GitHub webhook handler can submit an inventory request when a candidate branch changes routers, authentication middleware or service validation. Point `resources` at that branch and include its revision in the input. Retry with the same `Idempotency-Key` only for the same request, so a delivery retry does not become an extra inventory session.

Collect the report with a session read or the key's configured webhook after the turn finishes. Compare public/protected classifications as well as route additions. A change to a middleware argument can alter access without adding any URL, so the diff should not stop at counting paths.

## Why run it on Rush?

Express lets a route's meaning emerge from mount prefixes, middleware order and service code. Rush lets an agent work through that tree in its own sandbox and prepare local fixtures without mixing test users, JWT settings or migrations into a developer's current environment. The output is a map of the app that was inspected, including the parts that could not run.

The recorded tool calls make it possible to ask why a route was marked public and trace that conclusion back to a registration and a local response. Multiple services can receive independent requests within the key's concurrency limit. Their reports remain separate instead of sharing one shell's environment variables or an ambiguous set of local ports.

## Frequently asked questions

### Does this work when routers are mounted in several files?

That is the main reason to trace from the entry point. In the example, controller paths acquire `/api` through another router file. The inventory keeps both the fully mounted path and the file that declares the handler.

### Will optional JWT middleware be marked unauthenticated?

It is marked as optional authentication, with its behavior explained. A request with no token can be allowed while a malformed token is rejected. That difference matters for clients that send a stale header on an otherwise public read.

### Can route comments supply the parameter list?

Comments help locate intent, but handlers and service code determine which values the app reads. The agent follows nested bodies, numeric conversions and validation. A comment disagreeing with a router declaration is reported as documentation drift.

### Does the report also fix authorization problems?

This request returns an inventory and potential findings only. It leaves application code and upstream repositories unchanged. A confirmed issue needs its own authorized fix with tests for both allowed and denied requests.
