introduce TRPC and service layer

This commit is contained in:
Michael Dausmann
2023-02-05 11:55:49 +11:00
parent 791192a1ae
commit bba070d985
13 changed files with 307 additions and 58 deletions

View File

@@ -1,25 +0,0 @@
import { PrismaClient } from '@prisma/client';
import { serverSupabaseClient } from '#supabase/server';
const prisma = new PrismaClient();
export default defineEventHandler(async (event) => {
const client = serverSupabaseClient(event)
const user = await client.auth.getUser();
const dbUser = await prisma.user.findFirstOrThrow({
where: {
supabase_uid: user.data.id // TODO - this shit is messy.. typing
},
include: {
membership: true, // Return all fields
},
});
const data = await prisma.note.findMany({
where:{
account_id: dbUser.membership?.account_id
}
});
return data;
})

37
server/api/trpc/[trpc].ts Normal file
View File

@@ -0,0 +1,37 @@
/**
* This is the API-handler of your app that contains all your API routes.
* On a bigger app, you will probably want to split this file up into multiple files.
*/
import { createNuxtApiHandler } from 'trpc-nuxt'
import { z } from 'zod'
import { publicProcedure, router } from '~/server/trpc/trpc'
import { createContext } from '~~/server/trpc/context';
import NotesService from '~~/lib/services/notes.service';
export const appRouter = router({
notes: publicProcedure
.input(
z.object({
text: z.string().nullish(),
}),
)
.query(async ({ ctx, input }) => {
const notesService = new NotesService(ctx.prisma);
const notes = await notesService.getNotesForAccountId(ctx.dbUser.membership?.account_id);
return {
notes,
}
}),
})
// export only the type definition of the API
// None of the actual implementation is exposed to the client
export type AppRouter = typeof appRouter;
// export API handler
export default createNuxtApiHandler({
router: appRouter,
createContext: createContext,
onError({ error}) { console.error(error)}, // TODO - logging and reporting
})

43
server/trpc/context.ts Normal file
View File

@@ -0,0 +1,43 @@
import { PrismaClient } from '@prisma/client';
import type { inferAsyncReturnType } from '@trpc/server'
import { H3Event } from 'h3';
import { serverSupabaseClient } from '#supabase/server';
import SupabaseClient from '@supabase/supabase-js/dist/module/SupabaseClient';
import { User } from '@supabase/supabase-js';
import UserService from '~~/lib/services/user.service';
let prisma: PrismaClient | undefined
let supabase: SupabaseClient | undefined
let user: User | null = null;
let dbUser: any | undefined
export async function createContext(event: H3Event){
if (!supabase) {
supabase = serverSupabaseClient(event)
}
if (!user) {
({data: { user }} = await supabase.auth.getUser());
}
if (!prisma) {
prisma = new PrismaClient()
}
if (!dbUser && user) {
const userService = new UserService(prisma);
dbUser = await userService.getUserBySupabaseId(user.id);
if (!dbUser && user) {
dbUser = await userService.createUser( user.id, user.user_metadata.full_name );
console.log(`\n Created user \n ${JSON.stringify(dbUser)}\n`);
}
}
// TODO - This seems excessive, trim context when I have figured out what I actually need
return {
supabase,
user,
prisma,
dbUser,
}
};
export type Context = inferAsyncReturnType<typeof createContext>

21
server/trpc/trpc.ts Normal file
View File

@@ -0,0 +1,21 @@
/**
* This is your entry point to setup the root configuration for tRPC on the server.
* - `initTRPC` should only be used once per app.
* - We export only the functionality that we use so we can enforce which base procedures should be used
*
* Learn how to create protected base procedures and other things below:
* @see https://trpc.io/docs/v10/router
* @see https://trpc.io/docs/v10/procedures
*/
import { initTRPC } from '@trpc/server'
import { Context } from './context';
const t = initTRPC.context<Context>().create()
/**
* Unprotected procedure
**/
export const publicProcedure = t.procedure;
export const router = t.router;
export const middleware = t.middleware;