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" }}
|
{{ error?.statusCode || "Error" }}
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-xl mb-6">
|
<p class="text-xl mb-6">
|
||||||
{{ error?.message || "Something went wrong" }}
|
{{ error?.statusMessage || "Something went wrong" }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,32 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { idSchema } from "~/types/id";
|
|
||||||
|
|
||||||
const { params } = useRoute();
|
const { params } = useRoute();
|
||||||
const routeParam = params.id;
|
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({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode,
|
||||||
statusMessage: "Invalid recipe id",
|
statusMessage: "Invalid recipe id",
|
||||||
|
message: error.value.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
|
||||||
data: recipe,
|
|
||||||
pending,
|
|
||||||
error,
|
|
||||||
} = await useFetch(`/api/recipes/${id}`, {
|
|
||||||
lazy: true,
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div v-if="pending">Loading</div>
|
<div v-if="pending">Loading</div>
|
||||||
<div v-else-if="error">Failed: {{ error.statusMessage }}</div>
|
|
||||||
<section v-else>
|
<section v-else>
|
||||||
<Recipe :recipe="recipe" />
|
<Recipe :recipe="recipe!" />
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,3 @@
|
||||||
<script setup lang="ts">
|
|
||||||
const { data } = useGreeting("chef");
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="hero min-h-full bg-base-200">
|
<div class="hero min-h-full bg-base-200">
|
||||||
<div class="hero-content flex-col lg:flex-row-reverse">
|
<div class="hero-content flex-col lg:flex-row-reverse">
|
||||||
|
|
@ -9,7 +5,6 @@ const { data } = useGreeting("chef");
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-5xl font-bold prose">Eat Something New</h1>
|
<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>
|
<p class="py-6 prose">Generate a random recipe.</p>
|
||||||
<NuxtLink to="/random" class="btn btn-primary">
|
<NuxtLink to="/random" class="btn btn-primary">
|
||||||
Random Recipe Now
|
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");
|
const authorization = getRequestHeader(event, "authorization");
|
||||||
async function getUserFromHeader() {
|
async function getUserFromHeader() {
|
||||||
if (authorization) {
|
if (authorization) {
|
||||||
console.log("authorization:", authorization);
|
|
||||||
return { isAdmin: true };
|
return { isAdmin: true };
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import type { inferRouterOutputs } from "@trpc/server";
|
import type { inferRouterOutputs } from "@trpc/server";
|
||||||
import { z } from "zod";
|
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: publicProcedure
|
||||||
hello: privateProcedure
|
hello: privateProcedure
|
||||||
.input(
|
.input(
|
||||||
|
|
@ -17,6 +18,7 @@ export const appRouter = router({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const appRouter = mergeRouters(helloRouter, recipeRouter);
|
||||||
// export type definition of API
|
// export type definition of API
|
||||||
export type AppRouter = typeof appRouter;
|
export type AppRouter = typeof appRouter;
|
||||||
export type RouterOutput = inferRouterOutputs<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 publicProcedure = t.procedure;
|
||||||
export const router = t.router;
|
export const router = t.router;
|
||||||
export const middleware = t.middleware;
|
export const middleware = t.middleware;
|
||||||
|
export const mergeRouters = t.mergeRouters;
|
||||||
|
|
||||||
export const authMiddleware = middleware(({ next, ctx }) => {
|
export const authMiddleware = middleware(({ next, ctx }) => {
|
||||||
if (!ctx.user?.isAdmin) {
|
if (!ctx.user?.isAdmin) {
|
||||||
|
|
@ -22,4 +23,5 @@ export const authMiddleware = middleware(({ next, ctx }) => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export const privateProcedure = t.procedure.use(authMiddleware);
|
export const privateProcedure = t.procedure.use(authMiddleware);
|
||||||
|
|
|
||||||
10
types/id.ts
10
types/id.ts
|
|
@ -1,8 +1,6 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const idSchema = z
|
export const idSchema = z.string({
|
||||||
.number({
|
required_error: "recipe id is required",
|
||||||
required_error: "recipe id is required",
|
invalid_type_error: "recipe id must be a number",
|
||||||
invalid_type_error: "recipe id must be a number",
|
});
|
||||||
})
|
|
||||||
.positive("recipe id must be positive");
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue