Guide
API documentation
An OpenAPI 3.0 document, generated from the decorators you already wrote. No annotations, no separate spec file to keep in step, and nothing to remember when an endpoint changes.
What you get
setupSwagger serves two things. The spec itself is always available at
{path}/json; the browser UI at {path} needs
swagger-ui-express, which the generated project installs for you.
setupSwagger(app, {
title: 'my-api API',
version: '1.0.0',
basePath: MOUNT_PATH,
appId: APP_ID,
});
Call it after the registries have run, or the spec is generated before the endpoints
exist and comes back nearly empty. The generated app.ts already has it in the
right place.
Every option
setupSwagger(app, config, path?). The third argument is where the docs mount; it defaults to /api-docs.
| Option | Default | What it does |
|---|---|---|
title | required | Shown as the document title |
version | required | Your API's version, not the library's |
description | Auto-generated API documentation | Free text under the title |
basePath | the configured mountPath | The server URL requests are built against |
appId | — | Shown in the Authorize dialog, so nobody has to guess it |
restApiKey | false | Whether the docs require X-Parse-REST-API-Key |
host, schemes | — | Carried through for OpenAPI 2 style consumers |
| 3rd argument | '/api-docs' | Mount path. The spec is always at {path}/json |
Turning it on and off
There is deliberately no enabled option. The way to not have documentation is to
not mount it, so the switch belongs to your project rather than to the library:
if (DOCS_ENABLED) {
setupSwagger(app, {title, version, appId: APP_ID}, DOCS_PATH);
}
The generated project already has this, reading DOCS_ENABLED and
DOCS_PATH from .env — so switching docs off is an environment
variable, not a code change, and the startup banner reports
off (DOCS_ENABLED=false) rather than advertising a URL that answers nothing.
That is a deliberate choice, not an oversight. The document lists only the endpoints you
declared, generated from the same decorators that enforce them, so it cannot drift into
describing something that is not there — and a public API benefits from published
documentation. Set DOCS_ENABLED=false if your API is private and you would
rather not publish its shape. It is not an access control either way: hiding the map is not
locking the door.
Where the content comes from
Nothing here is written twice. Every part of the document is read from something that already had to exist:
| In the spec | Comes from |
|---|---|
| Schemas | @ParseClass and every @ParseField — type, required, description |
| Paths | @Route + the method name. createNote becomes POST /api/notes/createNote |
| Parameters or request body | validation.fields |
| Security | requiresAuth, requireRoles, validation.requireUser |
| Summaries, tags, responses | the swagger block on @CloudFunction |
A model with no @ParseClass is absent from the schemas, and a function with no
@Route is documented at its /functions/{name} path instead. Both are
worth knowing when something you expected is missing.
A browser cannot send a body on a GET, so those methods emit
parameters: [{in: 'query'}] and everything else emits a JSON
requestBody. This matches how validateEntityRoutes merges the query
string into the body — which is also why GET parameters arrive as strings and need
converting in your handler.
Tell the page your application id
Every request needs X-Parse-Application-Id, and a docs page that does not say which
value is a guessing game. A wrong guess comes back as a bare
{"error":"unauthorized"} that names nothing — so the endpoint looks broken when the
only problem is the header.
setupSwagger(app, {title, version, appId: APP_ID});
The Authorize dialog then reads Parse Application ID. This server: my-api. The
application id is not a secret — every client sends it on every request. The master key is the
secret, and it is never rendered into the page.
The REST API key is opt-in
Parse only enforces X-Parse-REST-API-Key when restAPIKey is configured
on the server, which most deployments — and every project psk new generates — do
not do. The spec therefore does not require it by default. Turn it on when you have one:
setupSwagger(app, {title, version, restApiKey: true});
Before 3.0.3 it was asserted unconditionally, which put a header that did nothing into every example the page produced and implied a gate that was not there.
How auth appears in the document
An endpoint that declares requiresAuth or requireRoles is documented
as needing a session token or the master key. One that declares neither is documented as open,
because it is.
| Declared | Documented as |
|---|---|
| nothing | application id only |
requiresAuth: true | application id + session token, or + master key |
requireRoles: [...] | the same — the role check happens after authentication |
validation: {requireUser: true} | the same, via Parse Server's own validator |
The document describes what the decorators enforce. It is not itself a control: a padlock in the page means an endpoint said it needed a session, not that anything checked.
Without swagger-ui-express
The UI package is optional. Without it, setupSwagger logs a warning, skips the
browser page, and still serves the spec:
# works either way
curl http://localhost:1337/api-docs/json
That is enough for anything that consumes a spec rather than reads one — client generation, a
contract test, an API gateway. If /api-docs returns Cannot GET while
/api-docs/json works, the package is simply not installed.
It is generated once
The document is built on the first request and reused until something registers, keyed on the registry's revision rather than a flag — so a late registration still invalidates it and nothing has to remember to. Endpoints added at boot are always included.
Next
- Endpoints — the decorator whose options this page renders
- Models — where the schemas come from
- Decorator reference — every option, including the
swaggerblock