Server
Crea aplicaciones integrales con el framework de servidor de Nuxt. Puedes extraer datos de tu base de datos o de otro servidor, crear API o incluso generar contenido estático del lado del servidor, como un mapa del sitio o una fuente RSS, todo desde una única base de código.
-| server/
---| api/
-----| hello.ts # /api/hello
---| routes/
-----| bonjour.ts # /bonjour
---| middleware/
-----| log.ts # log all requests
Cada archivo debe exportar una función predeterminada definida con defineEventHandler()
o eventHandler()
(alias).
server/api/hello.ts
export default eventHandler((event) => {
return {
hello: "world",
};
});
pages/index.vue
<script setup lang="ts">
const { data } = await useFetch("/api/hello");
</script>
<template>
<pre>{{ data }}</pre>
</template>
Parámetros de ruta
Crea rutas dinámicas en el servidor utilizando corchetes en los nombres de archivo.
server/api/users/[id].ts
export default eventHandler((event) => {
const id = getRouterParam(event, "id");
return { id };
});
Matching HTTP Method
Los nombres de archivos de manejo pueden tener el sufijo .get
, .post
, .put
, .delete
, ... para que coincidan con el método HTTP de la solicitud.
server/api/users.post.ts
export default eventHandler((event) => {
// handle POST /api/users
});
También puedes usarlo index.[method].ts
dentro de un directorio para estructurar tu código de manera diferente, esto es útil para crear espacios de nombres de API.
server/api/users/index.post.ts
export default eventHandler((event) => {
// handle POST /api/users
});
Body Handling
Para manejar el cuerpo de la solicitud, usa readBody()
.
server/api/users.post.ts
export default eventHandler(async (event) => {
const body = await readBody(event);
// handle body
});
app.vue
<script setup lang="ts">
async function submit() {
const { body } = await $fetch("/api/users", {
method: "post",
body: { test: 123 },
});
}
</script>
Query Parameters
Para manejar los parámetros de consulta, usa getQuery()
.
server/api/search.ts
// /api/search?term=nuxt&page=1
export default eventHandler((event) => {
const query = getQuery(event);
return {
term: query.term,
page: query.page || 1,
};
});
Error Handling
Para manejar errores, lanza un error HTTP usando createError()
.
server/api/secret.ts
export default eventHandler((event) => {
const authorized = false; // replace with your auth logic
if (!authorized) {
throw createError({ statusCode: 401, statusMessage: "Unauthorized" });
}
return {
secret: "42",
};
});
Status Codes
Para devolver un código de estado HTTP personalizado, usa setResponseStatus()
.
server/api/custom-status.ts
export default eventHandler((event) => {
setResponseStatus(event, 201);
return { message: "Created" };
});
Sending Redirect
server/api/foo.get.ts
export default defineEventHandler(async (event) => {
await sendRedirect(event, "/path/redirect/to", 302);
});
Ejemplo con NuxtUI
server\api\users\index.get.ts
export default eventHandler(() => {
return [
{ id: 1, username: "user1", email: "user1@mail.com" },
{ id: 2, username: "user2", email: "user2@mail.com" },
{ id: 3, username: "user3", email: "user3@mail.com" },
];
});
server\api\users[id].get.ts
export default eventHandler((event) => {
const id = Number(getRouterParam(event, "id"));
const users = [
{ id: 1, username: "user1", email: "user1@mail.com" },
{ id: 2, username: "user2", email: "user2@mail.com" },
{ id: 3, username: "user3", email: "user3@mail.com" },
];
return users.find((u) => u.id === id);
});
server\api\users\index.post.ts
import { formSquema } from "~~/shared/zod/zod.user";
export default eventHandler(async (event) => {
const body = await readBody(event);
const parsed = formSquema.safeParse(body);
if (!parsed.success) {
throw createError({
statusCode: 400,
statusMessage: "Error Zod backend",
});
}
return { ok: true };
});
shared\zod\zod.user.ts
import * as z from "zod";
export const formSquema = z.object({
username: z
.string()
.trim()
.min(1, "Escribe algo por favor")
.max(255, "Te agilaste"),
email: z.email("Correo no weno"),
});
export type FormSquemaType = z.infer<typeof formSquema>;
Frontend
app\pages\admin\users\index.vue
<script setup lang="ts">
const { data: users } = await useFetch("/api/users");
</script>
<template>
<div>
<h1>Users</h1>
<p>{{ users }}</p>
</div>
</template>
app\pages\admin\users[id].vue
<script setup lang="ts">
const { params } = useRoute();
const { data: user } = useFetch(`/api/users/${params.id}`);
</script>
<template>
<div>
<h1>User: {{ params.id }}</h1>
<pre>
{{ user }}
</pre>
</div>
</template>
app\pages\admin\users\create.vue
<script setup lang="ts">
import type { FormSubmitEvent } from "@nuxt/ui";
import type { FormSquemaType } from "~~/shared/zod/zod.user";
import { formSquema } from "~~/shared/zod/zod.user";
const state = reactive<Partial<FormSquemaType>>({
username: "",
email: "",
});
const toast = useToast();
const onSubmit = async (event: FormSubmitEvent<FormSquemaType>) => {
// const { data, error } = await useFetch("/api/users", {
// method: "POST",
// body: event.data,
// });
// console.log({ data: data.value, error: error.value });
// if (error) {
// toast.add({
// title: "Error",
// description: "Zod error",
// color: "error",
// });
// return;
// }
try {
const data = await $fetch("/api/users", {
method: "POST",
body: event.data,
});
console.log({ data });
toast.add({
title: "Success",
description: "Formulario procesado",
color: "success",
});
} catch (error) {
console.log({ error });
toast.add({
title: "Error",
description: "Zod error",
color: "error",
});
}
};
</script>
<template>
<div>
<h1>Create new User</h1>
<UForm
:schema="formSquema"
:state="state"
class="space-y-2"
@submit="onSubmit"
>
<UFormField
label="Username"
name="username"
>
<UInput v-model="state.username" />
</UFormField>
<UFormField
label="Email"
name="email"
>
<UInput
v-model="state.email"
type="email"
/>
</UFormField>
<UButton type="submit"> Submit </UButton>
</UForm>
</div>
</template>