QUESTPIE
AgentsOpenapi

Configuration

Everything config/openapi.ts accepts, what each option defaults to when you leave it out, and the two fields that are declared but never read.

View markdown
OptionTypeDefaultWhat it sets
info.titlestring"QUESTPIE API"The document title
info.versionstring"1.0.0"The document version
info.descriptionstringdroppedThe document description
serversArray<{ url; description? }>droppedScalar's environment switcher
basePathstring"/"The prefix on every generated path
exclude.collectionsstring[][]Collections to leave out
exclude.globalsstring[][]Globals to leave out
authbooleanincludedSet false to drop the auth paths
searchbooleanincludedSet false to drop the search paths
scalarScalarConfignoneThe reference UI, see below
specPathstringignoredDeclared in the type. Nothing reads it.
docsPathstringignoredDeclared in the type. Nothing reads it.

Every option is optional. Write the file with openApiConfig(), which returns its argument unchanged and exists only so the object is typed.

src/questpie/server/config/openapi.ts
import { openApiConfig } from "@questpie/openapi";

export default openApiConfig({
	info: { title: "My API", version: "2.0.0" },
	servers: [{ url: "https://api.example.com", description: "Production" }],
	basePath: "/api",
	exclude: { collections: ["auditLog"] },
	scalar: { theme: "purple", hideDownloadButton: true },
});

basePath

The generator joins this to every path as `${basePath}/${rest}`. It is a plain string concatenation, so the exact value matters.

You writeA collection called posts documents as
nothing//posts
basePath: "/"//posts
basePath: ""/posts
basePath: "/api"/api/posts
basePath: "/api/"/api//posts

Set it to the same value you pass createFetchHandler. If your handler sits at the root, write the empty string, not "/".

exclude

Both lists match on the registered name, the key you see on app.collections.<name> and app.globals.<name>. An excluded collection contributes no paths and no component schemas.

Excluding something hides it from the document. It does not close the endpoint. The route is still mounted and still runs its own access rules.

Both are on unless you write the literal false. The generator only checks for === false.

search: false is worth knowing about. The two search paths are emitted whether or not you configured a search adapter, so an app with no search still documents POST /search.

ScalarConfig

These go straight through to the reference UI. The page inlines them as JSON, next to the document itself.

OptionTypeDefaultWhat it does
themestring"purple"The Scalar theme name
titlestringthe document titleThe page <title>
customCssstringnoneCSS injected into the page
hideDownloadButtonbooleanScalar's own defaultHides the download button
defaultHttpClient{ targetKey; clientKey }Scalar's own defaultPreselects a client for code samples

defaultHttpClient takes Scalar's own keys, for example { targetKey: "shell", clientKey: "curl" }.

The page itself is a few lines of HTML. It inlines the whole document as JSON and loads @scalar/api-reference from cdn.jsdelivr.net. The CDN URL carries no version, so the page tracks whatever Scalar published last.

`scalar` only applies when you mount the route

openApiModule registers the docs route with no config argument. That makes it skip config/openapi.ts entirely. Your theme and title never reach it. See Serving it yourself.

specPath and docsPath

OpenApiModuleConfig declares both. Nothing in the package reads either one. The module mounts its routes under the fixed keys openapi.json and docs, so setting these changes nothing.

To serve the document somewhere else, mount the route factories yourself under the file name you want. Serving it yourself shows how.

Where the config comes from

Codegen matches the file config/openapi.ts and stores its default export under app.state.config.openapi. The spec route reads it from there when it builds the document.

Pass a config object to openApiRoute() or docsRoute() and that object replaces the file entirely. The two are not merged. Anything you leave out falls back to the defaults in the first table, not to what the file said.

On this page