Nuxt + Nitro typová inferencia: tRPC-like bezpečnosť bez nastavovania

Nuxt automaticky importuje typy serverových trás do klienta. Dostaneš kompletnú typovú bezpečnosť od konca ku koncu medzi API a frontendom bez extra knižnice, bez generovania kódu a bez schémy na udržiavanie.

·3 min čítania

Napíšeš API trasu na serveri. Zavoláš ju s useFetch alebo $fetch na klientovi. TypeScript pozná presný tvar odpovede – žiadne tRPC, žiadne generovanie kódu, žiadna extra konfigurácia.

Ak si používal tRPC s Reactom, Nuxt ti dá to isté s menším nastavením. Rozdiel je v tom, že to jednoducho funguje bez samostatného routera, adaptéra a providera na zapojenie.

Ako to funguje

Nuxt používa Nitro ako svoj serverový engine. Nitro môže odvodzovať návratový typ každej API trasy a vystaviť túto informáciu Nuxt klientskej vrstve.

Serverová trasa v server/api/posts.get.ts:

export default defineEventHandler(async () => {
  const posts = await db.select().from(postsTable)
  return posts
})

Na klientovi useFetch automaticky vie, čo toto vracia:

// data je typizovaná ako Post[] - nie je potrebná žiadna typová anotácia
const { data } = await useFetch('/api/posts')

TypeScript odvodzuje návratový typ priamo z handlera. Ak zmeníš tvar toho, čo trasa vracia, TypeScript oznámi každé call site, ktoré teraz nezodpovedá.

Mechanizmus

Nuxt generuje TypeScript deklarácie pre všetky tvoje serverové trasy do .nuxt/types/nitro.d.ts. Tieto deklarácie mapujú cesty trás na ich odvodené typy odpovedí. useFetch je typizovaný, aby tieto deklarácie konzumoval, takže návratový typ useFetch volania plynie priamo z návratového typu serverového handlera.

Žiadna schéma. Žiadny krok generovania kódu, ktorý si musíš pamätať spustiť. Žiadny samostatný klientský balíček na inštaláciu. Typy sa aktualizujú, keď uložíš súbor.

Typizované parametre trasy a query

Inferencia ide ďalej. Parametre handlera sú typizované tiež.

// server/api/posts/[id].get.ts
export default defineEventHandler(async (event) => {
  const { id } = getRouterParams(event)  // typizované ako string
  const post = await db.query.posts.findFirst({
    where: eq(posts.id, Number(id)),
  })
  if (!post) throw createError({ statusCode: 404 })
  return post
})
// klient - data je Post | null
const { data } = await useFetch(`/api/posts/${postId}`)

Query parametre, parsovanie body s readBody<T> a hlavičky majú typizované pomocníky tiež.

Porovnanie s tRPC

tRPC rieši rovnaký problém pre React/Next.js aplikácie. Definuješ procedúry na serveri a klient ich volá s plnou typovou bezpečnosťou. Je to vynikajúce riešenie, najmä pre komplexné aplikácie s mnohými procedúrami.

Nuxt prístup je ľahší:

AspekttRPCNuxt + Nitro
NastavenieRouter, adaptér, providerNič navyše
Klientské volaniatrpc.posts.query()useFetch('/api/posts')
Zdroj typovExportovaný typ routeraAuto-generované deklarácie
REST kompatibilitaNie (len RPC)Áno (štandardné HTTP)
Externé API volaniaVyžaduje wrapperProstý fetch funguje
ValidáciaZod/Valibot povinnéVoliteľné

Pre Nuxt projekt je vstavaná inferencia správnym predvoleným nastavením. Dostaneš typovú bezpečnosť naprieč stackom a tvoje API zostane štandardné REST API, ktoré môže volať akýkoľvek klient, nie tRPC-špecifický endpoint.

Pridanie validácie

Inferencia je odvodená, nie vynucovaná. Ak chceš runtime validáciu (a pre externý vstup by si mal), pridaj ju pomocou schéma knižnice.

import { z } from 'zod'

const CreatePostSchema = z.object({
  title: z.string().min(1),
  content: z.string().min(10),
})

export default defineEventHandler(async (event) => {
  const body = await readValidatedBody(event, CreatePostSchema.parse)
  // body je typizované ako { title: string; content: string }
  const post = await db.insert(posts).values(body).returning()
  return post[0]
})

readValidatedBody je Nitro utilita, ktorá validuje a vracia typizované body. Validovaný typ automaticky plynie ku klientovi.

Čo to znamená v praxi

Píšeš serverový kód, voláš ho z klienta, TypeScript ich udržiava synchronizované. Žiadna runtime správa schémy, žiadne extra nástroje na udržiavanie.

Je to menej explicitné ako tRPC, ale tiež neviditeľné – typy jednoducho fungujú a všimneš si ich iba keď sa niečo zmení na serveri a klient to okamžite označí.