mirror of
https://github.com/rjNemo/meal_planner
synced 2026-06-06 02:26:49 +00:00
use trpc for recipe router
This commit is contained in:
parent
767471f2bb
commit
a9f4df0071
11 changed files with 63 additions and 64 deletions
|
|
@ -1,4 +0,0 @@
|
|||
export default function useGreeting(text: string) {
|
||||
const { $client } = useNuxtApp();
|
||||
return $client.hello.useQuery({ text });
|
||||
}
|
||||
4
composables/useRecipeById.ts
Normal file
4
composables/useRecipeById.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export default function useRecipeById(id: number) {
|
||||
const { $client } = useNuxtApp();
|
||||
return $client.recipeGet.useQuery(id);
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
{{ error?.statusCode || "Error" }}
|
||||
</h1>
|
||||
<p class="text-xl mb-6">
|
||||
{{ error?.message || "Something went wrong" }}
|
||||
{{ error?.statusMessage || "Something went wrong" }}
|
||||
</p>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
<script setup lang="ts">
|
||||
import { idSchema } from "~/types/id";
|
||||
|
||||
const { params } = useRoute();
|
||||
const routeParam = params.id;
|
||||
|
||||
const parsed = idSchema.safeParse(routeParam);
|
||||
const id =
|
||||
typeof routeParam === "string" ? Number(routeParam) : Number(routeParam[0]);
|
||||
|
||||
const { data: recipe, pending, error } = await useRecipeById(id);
|
||||
|
||||
if (error.value) {
|
||||
let statusCode = 400;
|
||||
if (error.value.message === "Recipe not found") {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Recipe not found",
|
||||
});
|
||||
}
|
||||
|
||||
if (!parsed.success) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusCode,
|
||||
statusMessage: "Invalid recipe id",
|
||||
message: error.value.message,
|
||||
});
|
||||
}
|
||||
|
||||
const {
|
||||
data: recipe,
|
||||
pending,
|
||||
error,
|
||||
} = await useFetch(`/api/recipes/${id}`, {
|
||||
lazy: true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="pending">Loading</div>
|
||||
<div v-else-if="error">Failed: {{ error.statusMessage }}</div>
|
||||
<section v-else>
|
||||
<Recipe :recipe="recipe" />
|
||||
<Recipe :recipe="recipe!" />
|
||||
</section>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,3 @@
|
|||
<script setup lang="ts">
|
||||
const { data } = useGreeting("chef");
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="hero min-h-full bg-base-200">
|
||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||
|
|
@ -9,7 +5,6 @@ const { data } = useGreeting("chef");
|
|||
<div>
|
||||
<h1 class="text-5xl font-bold prose">Eat Something New</h1>
|
||||
|
||||
<p class="py-6 prose">{{ data?.greeting }}</p>
|
||||
<p class="py-6 prose">Generate a random recipe.</p>
|
||||
<NuxtLink to="/random" class="btn btn-primary">
|
||||
Random Recipe Now
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
import { parseRecipeData } from "~/utils/recipes";
|
||||
import type { Meal } from "~/types/recipe";
|
||||
import { idSchema } from "~/types/id";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { apiUrl } = useRuntimeConfig();
|
||||
const routeParam = getRouterParam(event, "id");
|
||||
|
||||
const parsed = idSchema.safeParse(routeParam);
|
||||
if (!parsed.success) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: "Invalid recipe id",
|
||||
message: parsed.error.message,
|
||||
});
|
||||
}
|
||||
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL(`lookup.php?i=${parsed.data}`, apiUrl).toString(),
|
||||
);
|
||||
if (!data?.meals) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Recipe not found",
|
||||
});
|
||||
}
|
||||
|
||||
const recipes = parseRecipeData(data);
|
||||
return recipes[0];
|
||||
});
|
||||
|
|
@ -8,7 +8,6 @@ export async function createContext(event: H3Event) {
|
|||
const authorization = getRequestHeader(event, "authorization");
|
||||
async function getUserFromHeader() {
|
||||
if (authorization) {
|
||||
console.log("authorization:", authorization);
|
||||
return { isAdmin: true };
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import type { inferRouterOutputs } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
import { publicProcedure, privateProcedure, router } from "../trpc";
|
||||
import { privateProcedure, router, mergeRouters } from "../trpc";
|
||||
import { recipeRouter } from "./recipes";
|
||||
|
||||
export const appRouter = router({
|
||||
export const helloRouter = router({
|
||||
// hello: publicProcedure
|
||||
hello: privateProcedure
|
||||
.input(
|
||||
|
|
@ -17,6 +18,7 @@ export const appRouter = router({
|
|||
}),
|
||||
});
|
||||
|
||||
export const appRouter = mergeRouters(helloRouter, recipeRouter);
|
||||
// export type definition of API
|
||||
export type AppRouter = typeof appRouter;
|
||||
export type RouterOutput = inferRouterOutputs<AppRouter>;
|
||||
|
|
|
|||
32
server/trpc/routers/recipes.ts
Normal file
32
server/trpc/routers/recipes.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import { z } from "zod";
|
||||
import { publicProcedure, router } from "../trpc";
|
||||
import type { Meal } from "~/types/recipe";
|
||||
import { parseRecipeData } from "~/utils/recipes";
|
||||
|
||||
const { apiUrl } = useRuntimeConfig();
|
||||
|
||||
export const recipeRouter = router({
|
||||
recipeGet: publicProcedure
|
||||
.input(
|
||||
z.coerce
|
||||
.number({
|
||||
required_error: "recipe id is required",
|
||||
invalid_type_error: "recipe id must be a number",
|
||||
})
|
||||
.positive("recipe id must be positive"),
|
||||
)
|
||||
.query(async ({ input }) => {
|
||||
const data = await $fetch<{ meals: Meal[] }>(
|
||||
new URL(`lookup.php?i=${input}`, apiUrl).href,
|
||||
);
|
||||
if (!data?.meals) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: "Recipe not found",
|
||||
});
|
||||
}
|
||||
|
||||
const recipes = parseRecipeData(data);
|
||||
return recipes[0];
|
||||
}),
|
||||
});
|
||||
|
|
@ -11,6 +11,7 @@ const t = initTRPC.context<Context>().create();
|
|||
export const publicProcedure = t.procedure;
|
||||
export const router = t.router;
|
||||
export const middleware = t.middleware;
|
||||
export const mergeRouters = t.mergeRouters;
|
||||
|
||||
export const authMiddleware = middleware(({ next, ctx }) => {
|
||||
if (!ctx.user?.isAdmin) {
|
||||
|
|
@ -22,4 +23,5 @@ export const authMiddleware = middleware(({ next, ctx }) => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
export const privateProcedure = t.procedure.use(authMiddleware);
|
||||
|
|
|
|||
10
types/id.ts
10
types/id.ts
|
|
@ -1,8 +1,6 @@
|
|||
import { z } from "zod";
|
||||
|
||||
export const idSchema = z
|
||||
.number({
|
||||
required_error: "recipe id is required",
|
||||
invalid_type_error: "recipe id must be a number",
|
||||
})
|
||||
.positive("recipe id must be positive");
|
||||
export const idSchema = z.string({
|
||||
required_error: "recipe id is required",
|
||||
invalid_type_error: "recipe id must be a number",
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue