Skip to content

Commit 1247cd3

Browse files
authored
feat: new schema endpoints (#145)
1 parent 8aef090 commit 1247cd3

File tree

8 files changed

+1068
-22
lines changed

8 files changed

+1068
-22
lines changed

openapi3.yaml

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,161 @@ paths:
160160
$ref: '#/components/responses/400BadRequest'
161161
'500':
162162
$ref: '#/components/responses/500InternalServerError'
163+
/schema/index:
164+
get:
165+
operationId: getSchemasIndex
166+
summary: Get searchable index of all schemas
167+
description: Returns metadata for all schemas. Frontend can build client-side search index from this data.
168+
responses:
169+
'200':
170+
description: OK
171+
content:
172+
application/json:
173+
schema:
174+
type: object
175+
required:
176+
- schemas
177+
properties:
178+
schemas:
179+
type: array
180+
items:
181+
type: object
182+
required:
183+
- id
184+
- name
185+
- path
186+
- version
187+
- category
188+
properties:
189+
id:
190+
type: string
191+
format: uri
192+
name:
193+
type: string
194+
path:
195+
type: string
196+
version:
197+
type: string
198+
description:
199+
type: string
200+
category:
201+
type: string
202+
title:
203+
type: string
204+
'404':
205+
$ref: '#/components/responses/404NotFound'
206+
'500':
207+
$ref: '#/components/responses/500InternalServerError'
208+
/schema/full:
209+
get:
210+
operationId: getFullSchema
211+
summary: Get comprehensive schema metadata
212+
parameters:
213+
- name: id
214+
in: query
215+
description: The id of the requested schema
216+
required: true
217+
schema:
218+
$ref: '#/components/schemas/schemaId'
219+
responses:
220+
'200':
221+
description: OK
222+
content:
223+
application/json:
224+
schema:
225+
type: object
226+
required:
227+
- id
228+
- name
229+
- path
230+
- version
231+
- category
232+
- rawContent
233+
- dereferencedContent
234+
- dependencies
235+
- envVars
236+
properties:
237+
id:
238+
type: string
239+
format: uri
240+
name:
241+
type: string
242+
path:
243+
type: string
244+
version:
245+
type: string
246+
category:
247+
type: string
248+
description:
249+
type: string
250+
title:
251+
type: string
252+
rawContent:
253+
type: object
254+
additionalProperties: true
255+
description: Raw JSON Schema
256+
dereferencedContent:
257+
type: object
258+
additionalProperties: true
259+
description: Schema with all $refs resolved
260+
typeContent:
261+
type: string
262+
nullable: true
263+
description: TypeScript type definitions
264+
dependencies:
265+
type: object
266+
required:
267+
- parents
268+
- children
269+
properties:
270+
parents:
271+
type: array
272+
items:
273+
$ref: '#/components/schemas/schemaReference'
274+
description: All parent schemas that reference this schema (nested tree structure)
275+
children:
276+
type: array
277+
items:
278+
$ref: '#/components/schemas/schemaReference'
279+
description: All child schemas referenced by this schema (nested tree structure)
280+
envVars:
281+
type: array
282+
items:
283+
type: object
284+
required:
285+
- envVariable
286+
- configPath
287+
properties:
288+
envVariable:
289+
type: string
290+
description: Environment variable name
291+
configPath:
292+
type: string
293+
description: JSON path to the property (e.g., "db.host")
294+
format:
295+
type: string
296+
description: Format hint (from x-env-format or format field)
297+
type:
298+
type: string
299+
description: JSON schema type (e.g., "string", "integer")
300+
required:
301+
type: boolean
302+
description: Whether this field is required
303+
description:
304+
type: string
305+
description: Schema description
306+
default:
307+
description: Default value (any type)
308+
refLink:
309+
type: string
310+
format: uri
311+
description: External schema reference if this env var comes from a $ref
312+
'400':
313+
$ref: '#/components/responses/400BadRequest'
314+
'404':
315+
$ref: '#/components/responses/404NotFound'
316+
'500':
317+
$ref: '#/components/responses/500InternalServerError'
163318
/capabilities:
164319
get:
165320
operationId: getCapabilities
@@ -468,6 +623,29 @@ components:
468623
$ref: '#/components/schemas/schemaTree'
469624
name:
470625
type: string
626+
schemaReference:
627+
type: object
628+
required:
629+
- id
630+
- name
631+
properties:
632+
id:
633+
type: string
634+
format: uri
635+
description: Schema ID
636+
name:
637+
type: string
638+
description: Schema name
639+
children:
640+
type: array
641+
items:
642+
$ref: '#/components/schemas/schemaReference'
643+
description: Nested child schemas (recursive)
644+
parents:
645+
type: array
646+
items:
647+
$ref: '#/components/schemas/schemaReference'
648+
description: Nested parent schemas (recursive)
471649
config:
472650
type: object
473651
additionalProperties: false

src/openapiTypes.d.ts

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,43 @@ export type paths = {
8585
patch?: never;
8686
trace?: never;
8787
};
88+
'/schema/index': {
89+
parameters: {
90+
query?: never;
91+
header?: never;
92+
path?: never;
93+
cookie?: never;
94+
};
95+
/**
96+
* Get searchable index of all schemas
97+
* @description Returns metadata for all schemas. Frontend can build client-side search index from this data.
98+
*/
99+
get: operations['getSchemasIndex'];
100+
put?: never;
101+
post?: never;
102+
delete?: never;
103+
options?: never;
104+
head?: never;
105+
patch?: never;
106+
trace?: never;
107+
};
108+
'/schema/full': {
109+
parameters: {
110+
query?: never;
111+
header?: never;
112+
path?: never;
113+
cookie?: never;
114+
};
115+
/** Get comprehensive schema metadata */
116+
get: operations['getFullSchema'];
117+
put?: never;
118+
post?: never;
119+
delete?: never;
120+
options?: never;
121+
head?: never;
122+
patch?: never;
123+
trace?: never;
124+
};
88125
'/capabilities': {
89126
parameters: {
90127
query?: never;
@@ -192,6 +229,19 @@ export type components = {
192229
children: components['schemas']['schemaTree'];
193230
name: string;
194231
};
232+
schemaReference: {
233+
/**
234+
* Format: uri
235+
* @description Schema ID
236+
*/
237+
id: string;
238+
/** @description Schema name */
239+
name: string;
240+
/** @description Nested child schemas (recursive) */
241+
children?: components['schemas']['schemaReference'][];
242+
/** @description Nested parent schemas (recursive) */
243+
parents?: components['schemas']['schemaReference'][];
244+
};
195245
config: {
196246
configName: components['schemas']['configName'];
197247
schemaId: components['schemas']['schemaId'];
@@ -486,6 +536,110 @@ export interface operations {
486536
500: components['responses']['500InternalServerError'];
487537
};
488538
};
539+
getSchemasIndex: {
540+
parameters: {
541+
query?: never;
542+
header?: never;
543+
path?: never;
544+
cookie?: never;
545+
};
546+
requestBody?: never;
547+
responses: {
548+
/** @description OK */
549+
200: {
550+
headers: {
551+
[name: string]: unknown;
552+
};
553+
content: {
554+
'application/json': {
555+
schemas: {
556+
/** Format: uri */
557+
id: string;
558+
name: string;
559+
path: string;
560+
version: string;
561+
description?: string;
562+
category: string;
563+
title?: string;
564+
}[];
565+
};
566+
};
567+
};
568+
500: components['responses']['500InternalServerError'];
569+
};
570+
};
571+
getFullSchema: {
572+
parameters: {
573+
query: {
574+
/** @description The id of the requested schema */
575+
id: components['schemas']['schemaId'];
576+
};
577+
header?: never;
578+
path?: never;
579+
cookie?: never;
580+
};
581+
requestBody?: never;
582+
responses: {
583+
/** @description OK */
584+
200: {
585+
headers: {
586+
[name: string]: unknown;
587+
};
588+
content: {
589+
'application/json': {
590+
/** Format: uri */
591+
id: string;
592+
name: string;
593+
path: string;
594+
version: string;
595+
category: string;
596+
description?: string;
597+
title?: string;
598+
/** @description Raw JSON Schema */
599+
rawContent: {
600+
[key: string]: unknown;
601+
};
602+
/** @description Schema with all $refs resolved */
603+
dereferencedContent: {
604+
[key: string]: unknown;
605+
};
606+
/** @description TypeScript type definitions */
607+
typeContent?: string | null;
608+
dependencies: {
609+
/** @description All parent schemas that reference this schema (nested tree structure) */
610+
parents: components['schemas']['schemaReference'][];
611+
/** @description All child schemas referenced by this schema (nested tree structure) */
612+
children: components['schemas']['schemaReference'][];
613+
};
614+
envVars: {
615+
/** @description Environment variable name */
616+
envVariable: string;
617+
/** @description JSON path to the property (e.g., "db.host") */
618+
configPath: string;
619+
/** @description Format hint (from x-env-format or format field) */
620+
format?: string;
621+
/** @description JSON schema type (e.g., "string", "integer") */
622+
type?: string;
623+
/** @description Whether this field is required */
624+
required?: boolean;
625+
/** @description Schema description */
626+
description?: string;
627+
/** @description Default value (any type) */
628+
default?: unknown;
629+
/**
630+
* Format: uri
631+
* @description External schema reference if this env var comes from a $ref
632+
*/
633+
refLink?: string;
634+
}[];
635+
};
636+
};
637+
};
638+
400: components['responses']['400BadRequest'];
639+
404: components['responses']['404NotFound'];
640+
500: components['responses']['500InternalServerError'];
641+
};
642+
};
489643
getCapabilities: {
490644
parameters: {
491645
query?: never;

src/schemas/controllers/schemaController.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,32 @@ export class SchemaController {
2828
const schemasTree = await this.manager.getSchemas();
2929
return res.status(httpStatus.OK).json(schemasTree);
3030
};
31+
32+
public getSchemasIndex: TypedRequestHandler<'/schema/index', 'get'> = async (req, res, next) => {
33+
try {
34+
const indexData = await this.manager.getSchemaIndex();
35+
36+
// Set cache headers
37+
res.setHeader('Cache-Control', 'public, max-age=3600'); // 1 hour
38+
39+
return res.status(httpStatus.OK).json(indexData);
40+
} catch (error) {
41+
next(error);
42+
}
43+
};
44+
45+
public getFullSchema: TypedRequestHandler<'/schema/full', 'get'> = async (req, res, next) => {
46+
try {
47+
const metadata = await this.manager.getFullSchemaMetadata(req.query.id);
48+
49+
return res.status(httpStatus.OK).json(metadata);
50+
} catch (error) {
51+
if (error instanceof SchemaNotFoundError) {
52+
(error as HttpError).status = httpStatus.NOT_FOUND;
53+
} else if (error instanceof SchemaPathIsInvalidError) {
54+
(error as HttpError).status = httpStatus.BAD_REQUEST;
55+
}
56+
next(error);
57+
}
58+
};
3159
}

0 commit comments

Comments
 (0)