Added zod for validation

This commit is contained in:
Denis Urs Rudolph
2025-12-12 12:21:03 +01:00
parent 2b164d6525
commit 7f6db6d004
4 changed files with 160 additions and 36 deletions

View File

@@ -1,54 +1,77 @@
import { z } from 'zod';
const API_URL = 'http://localhost:5000/api';
export interface Vehicle {
vin: string;
status: string;
currentVersion: string;
lastHeartbeat: string;
groupId?: number;
group?: VehicleGroup;
}
// --- Zod Schemas ---
export interface VehicleGroup {
id: number;
name: string;
description?: string;
vehicles?: Vehicle[];
}
// Base schemas to handle circular references if needed, though usually mapped by API
// defined separately to allow recursive type inference if we went down the z.lazy route,
// but for now we'll keep it simple as the API returns what it returns.
export interface FirmwareUpdate {
id: number;
version: string;
description?: string;
uploadedAt: string;
}
export const BaseVehicleGroupSchema = z.object({
id: z.number(),
name: z.string(),
description: z.string().optional().nullable(),
});
export interface Deployment {
id: number;
updateId: number;
targetVin?: string;
targetGroupId?: number;
status: string;
createdAt: string;
update: FirmwareUpdate;
}
export const VehicleSchema = z.object({
vin: z.string(),
status: z.string(),
currentVersion: z.string(),
lastHeartbeat: z.string(),
groupId: z.number().optional().nullable(),
group: BaseVehicleGroupSchema.optional().nullable(),
});
export const VehicleGroupSchema = BaseVehicleGroupSchema.extend({
vehicles: z.array(VehicleSchema).optional().nullable(),
});
export const FirmwareUpdateSchema = z.object({
id: z.number(),
version: z.string(),
description: z.string().optional().nullable(),
uploadedAt: z.string(),
});
export const DeploymentSchema = z.object({
id: z.number(),
updateId: z.number(),
targetVin: z.string().optional().nullable(),
targetGroupId: z.number().optional().nullable(),
status: z.string(),
createdAt: z.string(),
update: FirmwareUpdateSchema,
});
// --- Types Inferred from Schemas ---
export type Vehicle = z.infer<typeof VehicleSchema>;
export type VehicleGroup = z.infer<typeof VehicleGroupSchema>;
export type FirmwareUpdate = z.infer<typeof FirmwareUpdateSchema>;
export type Deployment = z.infer<typeof DeploymentSchema>;
// --- API Functions with Validation ---
export async function fetchVehicles(): Promise<Vehicle[]> {
const res = await fetch(`${API_URL}/admin/vehicles`);
if (!res.ok) throw new Error('Failed to fetch vehicles');
return res.json();
const json = await res.json();
return z.array(VehicleSchema).parse(json);
}
export async function fetchGroups(): Promise<VehicleGroup[]> {
const res = await fetch(`${API_URL}/admin/groups`);
if (!res.ok) throw new Error('Failed to fetch groups');
return res.json();
const json = await res.json();
return z.array(VehicleGroupSchema).parse(json);
}
export async function getUpdates(): Promise<FirmwareUpdate[]> {
const res = await fetch(`${API_URL}/admin/updates`);
if (!res.ok) throw new Error('Failed to fetch updates');
return res.json();
const json = await res.json();
return z.array(FirmwareUpdateSchema).parse(json);
}
export async function createGroup(name: string, description?: string): Promise<VehicleGroup> {
@@ -58,7 +81,8 @@ export async function createGroup(name: string, description?: string): Promise<V
body: JSON.stringify({ name, description }),
});
if (!res.ok) throw new Error('Failed to create group');
return res.json();
const json = await res.json();
return VehicleGroupSchema.parse(json);
}
export async function updateGroup(id: number, name: string, description?: string): Promise<VehicleGroup> {
@@ -68,7 +92,8 @@ export async function updateGroup(id: number, name: string, description?: string
body: JSON.stringify({ name, description }),
});
if (!res.ok) throw new Error('Failed to update group');
return res.json();
const json = await res.json();
return VehicleGroupSchema.parse(json);
}
export async function assignVehicleToGroup(groupId: number, vin: string): Promise<void> {
@@ -83,7 +108,8 @@ export async function assignVehicleToGroup(groupId: number, vin: string): Promis
export async function fetchDeployments(): Promise<Deployment[]> {
const res = await fetch(`${API_URL}/admin/deployments`);
if (!res.ok) throw new Error('Failed to fetch deployments');
return res.json();
const json = await res.json();
return z.array(DeploymentSchema).parse(json);
}
export async function uploadUpdate(formData: FormData): Promise<void> {