Schema Endpoint
Every OPRA HTTP adapter automatically registers a GET /$schema endpoint that returns the full API document in JSON format. No configuration is required — it is always available at the adapter's base path.
The $schema endpoint
GET {basePath}/$schema
Returns a JSON document describing the entire API: all controllers, operations, parameters, response types, and data type definitions.
curl http://localhost:3000/api/$schema
{
"spec": "1.0",
"id": "a3f8c1...",
"info": {
"title": "My API",
"version": "1.0.0"
},
"types": {
"Customer": { ... },
"Order": { ... }
},
"api": {
"transport": "http",
"name": "MyApi",
"url": "http://localhost:3000/api",
"controllers": {
"Customers": {
"path": "/customers",
"operations": { ... }
}
}
}
}
The schema is OPRA's own document format — not OpenAPI. OPRA clients use it to introspect the API, generate typed code, and validate requests.
The response is cached after the first call, so repeated fetches have no serialization cost.
Referenced documents
Large APIs can be split across multiple linked documents. When a schema references another document, clients fetch it separately using the ?id= query parameter:
GET {basePath}/$schema?id={documentId}
The id value comes from the references map in the root schema:
{
"references": {
"core": {
"id": "b9e2a4...",
"url": "http://core.internal/api/$schema"
}
}
}
The OPRA client handles recursive document fetching automatically — you don't need to implement this manually.
Accessing the document from code
Once an adapter is initialized, the raw document is available on adapter.document:
const adapter = new ExpressAdapter(app, document, { basePath: '/api' });
// Export the schema to JSON (same data as the HTTP endpoint)
const json = adapter.document.export({ scope: adapter.scope });
// Access the HTTP API definition
const httpApi = adapter.document.getHttpApi();
Scope
The scope option on the adapter controls which fields and types are included in the export. Fields or types that don't match the scope are omitted from the schema response:
new ExpressAdapter(app, document, {
basePath: '/api',
scope: 'public',
});
The same scope is applied consistently to both the HTTP endpoint and adapter.document.export().
Client-side usage
OpraHttpClient fetches and parses the schema automatically when you point it at the API root:
import { OpraHttpClient } from '@opra/client';
const client = new OpraHttpClient('http://localhost:3000/api');
// Fetch the schema and build a typed document object
const document = await client.fetchDocument();
The client recursively fetches any referenced documents and merges them into a single in-memory representation.
Code generation (CLI)
The oprimp CLI uses the $schema endpoint to generate TypeScript client code:
npx oprimp http://localhost:3000/api ./api-src/
This fetches the live schema and emits typed models and client stubs. The generated code is always in sync with the API because it is derived from the same document the adapter serves at runtime.