Adding type safety with Valibot
Not strictly nuxt related but I'm having trouble making my request data type safe with Valibot.
I have the schema defined in my server route:
But when I try to fetch it in the template VSCode doesn't pick up on any type safety:
import * as v from "valibot";
const scheduleSchema = v.object({
id: v.nullable(v.string()),
revision_id: v.optional(v.nullable(v.string())),
created: v.nullable(v.number()),
updated: v.nullable(v.number()),
name: v.nullable(v.string()),
lessons: v.nullable(
v.array(
v.object({
id: v.string(),
name: v.string(),
description: v.string(),
pages: v.array(v.object({})),
owner: v.string(),
track: v.string(),
audit: v.object({
available_at: v.nullable(v.number()),
completed_at: v.nullable(v.number()),
first_viewed_at: v.nullable(v.number()),
times_viewed: v.nullable(v.number()),
last_notified: v.nullable(v.number()),
}),
}),
),
),
owner: v.string(),
});
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const response = await api<{ schema: unknown }>(
event,
`${event.path.replace(/^\/api/, "")}`,
{
method: event.method,
params: {
type: query.path,
},
},
);
try {
return v.parse(scheduleSchema, response);
} catch (e) {
console.error(e);
return {};
}
});
import * as v from "valibot";
const scheduleSchema = v.object({
id: v.nullable(v.string()),
revision_id: v.optional(v.nullable(v.string())),
created: v.nullable(v.number()),
updated: v.nullable(v.number()),
name: v.nullable(v.string()),
lessons: v.nullable(
v.array(
v.object({
id: v.string(),
name: v.string(),
description: v.string(),
pages: v.array(v.object({})),
owner: v.string(),
track: v.string(),
audit: v.object({
available_at: v.nullable(v.number()),
completed_at: v.nullable(v.number()),
first_viewed_at: v.nullable(v.number()),
times_viewed: v.nullable(v.number()),
last_notified: v.nullable(v.number()),
}),
}),
),
),
owner: v.string(),
});
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const response = await api<{ schema: unknown }>(
event,
`${event.path.replace(/^\/api/, "")}`,
{
method: event.method,
params: {
type: query.path,
},
},
);
try {
return v.parse(scheduleSchema, response);
} catch (e) {
console.error(e);
return {};
}
});
<template>
<div class="grid gap-8">
<div class="prose prose-neutral">
<h1 class="mb-4">Hi {{ user.first_name }}!</h1>
<p class="mt-0">
Welcome back! Continue learning from where you left off.
</p>
</div>
<div class="flex">
<ModuleProgress class="flex-1" :progress="75" />
</div>
<pre>{{ data.name }}</pre>
</div>
</template>
<script lang="ts" setup>
const user = ref({ first_name: "James" });
const { data } = await useFetch("/api/users/me/schedule");
</script>
<template>
<div class="grid gap-8">
<div class="prose prose-neutral">
<h1 class="mb-4">Hi {{ user.first_name }}!</h1>
<p class="mt-0">
Welcome back! Continue learning from where you left off.
</p>
</div>
<div class="flex">
<ModuleProgress class="flex-1" :progress="75" />
</div>
<pre>{{ data.name }}</pre>
</div>
</template>
<script lang="ts" setup>
const user = ref({ first_name: "James" });
const { data } = await useFetch("/api/users/me/schedule");
</script>
1 Reply
FYI I fixed it by wrapping the schema object in a v.partial:
const scheduleSchema = v.partial(
v.object({
id: v.nullable(v.string()),
revision_id: v.optional(v.nullable(v.string())),
created: v.nullable(v.number()),
updated: v.nullable(v.number()),
name: v.nullable(v.string()),
lessons: v.nullable(
v.array(
v.object({
id: v.string(),
name: v.string(),
description: v.string(),
pages: v.array(v.object({})),
owner: v.string(),
track: v.string(),
audit: v.object({
available_at: v.nullable(v.number()),
completed_at: v.nullable(v.number()),
first_viewed_at: v.nullable(v.number()),
times_viewed: v.nullable(v.number()),
last_notified: v.nullable(v.number()),
}),
}),
),
),
owner: v.string(),
}),
);
const scheduleSchema = v.partial(
v.object({
id: v.nullable(v.string()),
revision_id: v.optional(v.nullable(v.string())),
created: v.nullable(v.number()),
updated: v.nullable(v.number()),
name: v.nullable(v.string()),
lessons: v.nullable(
v.array(
v.object({
id: v.string(),
name: v.string(),
description: v.string(),
pages: v.array(v.object({})),
owner: v.string(),
track: v.string(),
audit: v.object({
available_at: v.nullable(v.number()),
completed_at: v.nullable(v.number()),
first_viewed_at: v.nullable(v.number()),
times_viewed: v.nullable(v.number()),
last_notified: v.nullable(v.number()),
}),
}),
),
),
owner: v.string(),
}),
);