fix: openapi schemas

This commit is contained in:
charles-gauthereau
2026-05-28 19:05:57 +02:00
parent 1fbbc935c1
commit c3bafef6d8
4 changed files with 55 additions and 90 deletions
+2
View File
@@ -74,6 +74,8 @@ function checkRouteExists(pathname: string) {
/^\/api\/health\/?$/, /^\/api\/health\/?$/,
/^\/api\/google\/drive\/callback\/?$/, /^\/api\/google\/drive\/callback\/?$/,
// v1 external API // v1 external API
/^\/api\/v1\/docs\/?$/,
/^\/api\/v1\/openapi\/?$/,
/^\/api\/v1\/agents\/?$/, /^\/api\/v1\/agents\/?$/,
/^\/api\/v1\/agents\/[^/]+\/?$/, /^\/api\/v1\/agents\/[^/]+\/?$/,
/^\/api\/v1\/agents\/[^/]+\/key\/?$/, /^\/api\/v1\/agents\/[^/]+\/key\/?$/,
+10 -19
View File
@@ -1,23 +1,8 @@
import { z } from "zod"; import { z } from "zod";
import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi"; import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi";
import "@/lib/api-v1/openapi/registry"; import "@/lib/api-v1/openapi/registry";
import {AgentSchema} from "@/features/agents/agents.schema";
const AgentSchema = z import {agentSchema} from "@/db/schema/08_agent";
.object({
id: z.string().uuid(),
slug: z.string(),
version: z.string().nullable(),
name: z.string(),
healthErrorCount: z.number().int().nullable(),
description: z.string(),
isArchived: z.boolean().nullable(),
lastContact: z.string().datetime().nullable(),
organizationId: z.string().uuid().nullable(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime().nullable(),
deletedAt: z.string().datetime().nullable(),
})
.openapi("Agent");
const UuidParam = z const UuidParam = z
.string() .string()
@@ -25,15 +10,17 @@ const UuidParam = z
.openapi({ example: "123e4567-e89b-12d3-a456-426614174000" }); .openapi({ example: "123e4567-e89b-12d3-a456-426614174000" });
const security = [{ apiKeyAuth: [] }]; const security = [{ apiKeyAuth: [] }];
const tags = ["Agents"];
const ErrorSchema = z.object({ error: z.string() }); const ErrorSchema = z.object({ error: z.string() });
export function registerAgentRoutes(registry: OpenAPIRegistry) { export function registerAgentRoutes(registry: OpenAPIRegistry) {
registry.register("Agent", AgentSchema); registry.register("Agent", z.object(agentSchema.shape).openapi("Agent"));
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/agents", path: "/agents",
tags,
summary:"List agents", summary:"List agents",
security, security,
responses: { responses: {
@@ -41,7 +28,7 @@ export function registerAgentRoutes(registry: OpenAPIRegistry) {
description: "List of accessible agents", description: "List of accessible agents",
content: { content: {
"application/json": { "application/json": {
schema: z.object({ data: z.array(AgentSchema) }), schema: z.object({ data: z.array(agentSchema) }),
}, },
}, },
}, },
@@ -59,6 +46,7 @@ export function registerAgentRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "post", method: "post",
path: "/agents", path: "/agents",
tags,
summary:"Create an agent", summary:"Create an agent",
security, security,
request: { request: {
@@ -107,6 +95,7 @@ export function registerAgentRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/agents/{id}", path: "/agents/{id}",
tags,
summary:"Get agent by ID", summary:"Get agent by ID",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -139,6 +128,7 @@ export function registerAgentRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "delete", method: "delete",
path: "/agents/{id}", path: "/agents/{id}",
tags,
summary:"Delete agent", summary:"Delete agent",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -166,6 +156,7 @@ export function registerAgentRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/agents/{id}/key", path: "/agents/{id}/key",
tags,
summary:"Get agent edge key", summary:"Get agent edge key",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
+27 -59
View File
@@ -1,70 +1,36 @@
import { z } from "zod"; import { z } from "zod";
import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi"; import { OpenAPIRegistry } from "@asteasolutions/zod-to-openapi";
import "@/lib/api-v1/openapi/registry"; import "@/lib/api-v1/openapi/registry";
import { databaseSchema, backupSchema, restorationSchema } from "@/db/schema/07_database";
import { backupStorageSchema } from "@/db/schema/14_storage-backup";
const DbmsEnum = z.enum([ const datetimeNullable = z.string().datetime().nullable();
"postgresql", const datetime = z.string().datetime();
"mysql", const commonTimestamps = {
"mariadb", createdAt: datetime,
"mongodb", updatedAt: datetimeNullable,
"sqlite", deletedAt: datetimeNullable,
"redis", };
"valkey",
"firebird",
"mssql",
]);
const StatusEnum = z.enum(["waiting", "ongoing", "failed", "success"]);
const BackupStorageStatusEnum = z.enum(["pending", "success", "failed"]);
const DatabaseSchema = z const DatabaseSchema = z
.object({ .object({
id: z.string().uuid(), ...databaseSchema.shape,
agentDatabaseId: z.string().uuid(), lastContact: datetimeNullable,
name: z.string(), ...commonTimestamps,
dbms: DbmsEnum,
description: z.string().nullable(),
backupPolicy: z.string().nullable(),
isWaitingForBackup: z.boolean(),
backupToRestore: z.string().nullable(),
healthErrorCount: z.number().int().nullable(),
agentId: z.string().uuid(),
lastContact: z.string().datetime().nullable(),
projectId: z.string().uuid().nullable(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime().nullable(),
deletedAt: z.string().datetime().nullable(),
}) })
.openapi("Database"); .openapi("Database");
const BackupStorageSchema = z const BackupStorageSchema = z
.object({ .object({
id: z.string().uuid(), ...backupStorageSchema.shape,
backupId: z.string().uuid(), ...commonTimestamps,
storageChannelId: z.string().uuid(),
status: BackupStorageStatusEnum,
path: z.string().nullable(),
size: z.number().nullable(),
checksum: z.string().nullable(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime().nullable(),
deletedAt: z.string().datetime().nullable(),
}) })
.openapi("BackupStorage"); .openapi("BackupStorage");
const BackupSchema = z const BackupSchema = z
.object({ .object({
id: z.string().uuid(), ...backupSchema.shape,
status: StatusEnum, ...commonTimestamps,
file: z.string().nullable(),
fileSize: z.number().nullable(),
databaseId: z.string().uuid(),
imported: z.boolean().nullable(),
migrated: z.boolean().nullable(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime().nullable(),
deletedAt: z.string().datetime().nullable(),
}) })
.openapi("Backup"); .openapi("Backup");
@@ -74,14 +40,8 @@ const BackupWithStoragesSchema = BackupSchema.extend({
const RestorationSchema = z const RestorationSchema = z
.object({ .object({
id: z.string().uuid(), ...restorationSchema.shape,
status: StatusEnum, ...commonTimestamps,
backupStorageId: z.string().uuid().nullable(),
backupId: z.string().uuid(),
databaseId: z.string().uuid().nullable(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime().nullable(),
deletedAt: z.string().datetime().nullable(),
}) })
.openapi("Restoration"); .openapi("Restoration");
@@ -91,6 +51,7 @@ const UuidParam = z
.openapi({ example: "123e4567-e89b-12d3-a456-426614174000" }); .openapi({ example: "123e4567-e89b-12d3-a456-426614174000" });
const security = [{ apiKeyAuth: [] }]; const security = [{ apiKeyAuth: [] }];
const tags = ["Databases"];
const ErrorSchema = z.object({ error: z.string() }); const ErrorSchema = z.object({ error: z.string() });
@@ -104,6 +65,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/databases", path: "/databases",
tags,
summary:"List databases", summary:"List databases",
security, security,
responses: { responses: {
@@ -129,6 +91,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/databases/{id}", path: "/databases/{id}",
tags,
summary:"Get database by ID", summary:"Get database by ID",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -163,6 +126,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/databases/{id}/status", path: "/databases/{id}/status",
tags,
summary:"Get database status", summary:"Get database status",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -174,7 +138,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
schema: z.object({ schema: z.object({
data: z.object({ data: z.object({
isWaitingForBackup: z.boolean().nullable(), isWaitingForBackup: z.boolean().nullable(),
lastContact: z.string().datetime().nullable(), lastContact: datetimeNullable,
latestBackup: BackupSchema.nullable(), latestBackup: BackupSchema.nullable(),
latestRestoration: RestorationSchema.nullable(), latestRestoration: RestorationSchema.nullable(),
}), }),
@@ -204,6 +168,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/databases/{id}/backup", path: "/databases/{id}/backup",
tags,
summary:"List backups for a database", summary:"List backups for a database",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -238,6 +203,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "post", method: "post",
path: "/databases/{id}/backup", path: "/databases/{id}/backup",
tags,
summary:"Trigger a backup for a database", summary:"Trigger a backup for a database",
security, security,
request: { params: z.object({ id: UuidParam }) }, request: { params: z.object({ id: UuidParam }) },
@@ -274,6 +240,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "get", method: "get",
path: "/databases/{id}/backup/{backupId}", path: "/databases/{id}/backup/{backupId}",
tags,
summary:"Get a specific backup with storage details", summary:"Get a specific backup with storage details",
security, security,
request: { request: {
@@ -310,6 +277,7 @@ export function registerDatabaseRoutes(registry: OpenAPIRegistry) {
registry.registerPath({ registry.registerPath({
method: "post", method: "post",
path: "/databases/{id}/restore", path: "/databases/{id}/restore",
tags,
summary:"Restore a database from a backup", summary:"Restore a database from a backup",
security, security,
request: { request: {
+4
View File
@@ -21,5 +21,9 @@ export function buildSpec() {
}, },
servers: [{ url: "/api/v1" }], servers: [{ url: "/api/v1" }],
security: [{ apiKeyAuth: [] }], security: [{ apiKeyAuth: [] }],
tags: [
{ name: "Agents", description: "Agent management" },
{ name: "Databases", description: "Database management and backup operations" },
],
}); });
} }