feat: setup basic error handling on server

This commit is contained in:
Henry
2024-07-30 22:36:39 +01:00
parent 9931a585a5
commit 2033f37e72
7 changed files with 190 additions and 34 deletions

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { import {
createTRPCRouter, createTRPCRouter,
@@ -12,9 +13,15 @@ import * as userRepo from "~/server/db/repository/user.repo";
export const authRouter = createTRPCRouter({ export const authRouter = createTRPCRouter({
getUser: protectedProcedure.query(async ({ ctx }) => { getUser: protectedProcedure.query(async ({ ctx }) => {
if (!ctx.user?.id) return; const userId = ctx.user?.id;
const result = await userRepo.getById(ctx.db, ctx.user.id); if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const result = await userRepo.getById(ctx.db, userId);
return result; return result;
}), }),
@@ -33,7 +40,11 @@ export const authRouter = createTRPCRouter({
loginWithOAuth: publicProcedure loginWithOAuth: publicProcedure
.input(z.object({ provider: z.string() })) .input(z.object({ provider: z.string() }))
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
if (input.provider !== "google") return null; if (input.provider !== "google")
throw new TRPCError({
message: `Unsupported OAuth provider: ${input.provider}`,
code: "BAD_REQUEST",
});
const { data } = await ctx.db.auth.signInWithOAuth({ const { data } = await ctx.db.auth.signInWithOAuth({
provider: "google", provider: "google",

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
@@ -16,7 +17,11 @@ export const boardRouter = createTRPCRouter({
input.workspacePublicId, input.workspacePublicId,
); );
if (!workspace) return; if (!workspace)
throw new TRPCError({
message: `Workspace with public ID ${input.workspacePublicId} not found`,
code: "NOT_FOUND",
});
const result = boardRepo.getAllByWorkspaceId(ctx.db, workspace.id); const result = boardRepo.getAllByWorkspaceId(ctx.db, workspace.id);
@@ -39,14 +44,22 @@ export const boardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const workspace = await workspaceRepo.getByPublicId( const workspace = await workspaceRepo.getByPublicId(
ctx.db, ctx.db,
input.workspacePublicId, input.workspacePublicId,
); );
if (!workspace) return; if (!workspace)
throw new TRPCError({
message: `Workspace with public ID ${input.workspacePublicId} not found`,
code: "NOT_FOUND",
});
const result = await boardRepo.create(ctx.db, { const result = await boardRepo.create(ctx.db, {
name: input.name, name: input.name,
@@ -80,11 +93,22 @@ export const boardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const board = await boardRepo.getWithListIdsByPublicId( const board = await boardRepo.getWithListIdsByPublicId(
ctx.db, ctx.db,
input.boardPublicId, input.boardPublicId,
); );
if (!board || !userId) return;
if (!board)
throw new TRPCError({
message: `Board with public ID ${input.boardPublicId} not found`,
code: "NOT_FOUND",
});
const listIds = board.lists.map((list) => list.id); const listIds = board.lists.map((list) => list.id);

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
@@ -21,14 +22,22 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const list = await listRepo.getWithCardsByPublicId( const list = await listRepo.getWithCardsByPublicId(
ctx.db, ctx.db,
input.listPublicId, input.listPublicId,
); );
if (!list?.id) return; if (!list?.id)
throw new TRPCError({
message: `List with public ID ${input.listPublicId} not found`,
code: "NOT_FOUND",
});
const lastCard = list.cards.length && list.cards[0]; const lastCard = list.cards.length && list.cards[0];
@@ -60,7 +69,11 @@ export const cardRouter = createTRPCRouter({
input.labelPublicIds, input.labelPublicIds,
); );
if (!labels?.length) return; if (!labels?.length)
throw new TRPCError({
message: `Labels with public IDs ${input.labelPublicIds} not found`,
code: "NOT_FOUND",
});
const labelsInsert = labels.map((label) => ({ const labelsInsert = labels.map((label) => ({
cardId: newCardId, cardId: newCardId,
@@ -76,7 +89,11 @@ export const cardRouter = createTRPCRouter({
input.memberPublicIds, input.memberPublicIds,
); );
if (!members?.length) return; if (!members?.length)
throw new TRPCError({
message: `Members with public IDs ${input.memberPublicIds} not found`,
code: "NOT_FOUND",
});
const membersInsert = members.map((member) => ({ const membersInsert = members.map((member) => ({
cardId: newCardId, cardId: newCardId,
@@ -101,12 +118,26 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const card = await cardRepo.getByPublicId(ctx.db, input.cardPublicId); const card = await cardRepo.getByPublicId(ctx.db, input.cardPublicId);
const label = await labelRepo.getByPublicId(ctx.db, input.labelPublicId); const label = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
if (!card || !label) return; if (!card)
throw new TRPCError({
message: `Card with public ID ${input.cardPublicId} not found`,
code: "NOT_FOUND",
});
if (!label)
throw new TRPCError({
message: `Label with public ID ${input.labelPublicId} not found`,
code: "NOT_FOUND",
});
const cardLabelIds = { cardId: card.id, labelId: label.id }; const cardLabelIds = { cardId: card.id, labelId: label.id };
@@ -135,7 +166,11 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const card = await cardRepo.getByPublicId(ctx.db, input.cardPublicId); const card = await cardRepo.getByPublicId(ctx.db, input.cardPublicId);
const member = await workspaceRepo.getMemberByPublicId( const member = await workspaceRepo.getMemberByPublicId(
@@ -143,7 +178,17 @@ export const cardRouter = createTRPCRouter({
input.workspaceMemberPublicId, input.workspaceMemberPublicId,
); );
if (!card || !member) return; if (!card)
throw new TRPCError({
message: `Card with public ID ${input.cardPublicId} not found`,
code: "NOT_FOUND",
});
if (!member)
throw new TRPCError({
message: `Member with public ID ${input.workspaceMemberPublicId} not found`,
code: "NOT_FOUND",
});
const cardMemberIds = { cardId: card.id, memberId: member.id }; const cardMemberIds = { cardId: card.id, memberId: member.id };
@@ -183,7 +228,11 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const result = cardRepo.update( const result = cardRepo.update(
ctx.db, ctx.db,
@@ -202,14 +251,22 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const card = await cardRepo.getCardWithListByPublicId( const card = await cardRepo.getCardWithListByPublicId(
ctx.db, ctx.db,
input.cardPublicId, input.cardPublicId,
); );
if (!card ?? !card?.list?.id) return; if (!card ?? !card?.list?.id)
throw new TRPCError({
message: `Card with public ID ${input.cardPublicId} not found`,
code: "NOT_FOUND",
});
const deletedAt = new Date().toISOString(); const deletedAt = new Date().toISOString();
@@ -235,14 +292,22 @@ export const cardRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const card = await cardRepo.getCardWithListByPublicId( const card = await cardRepo.getCardWithListByPublicId(
ctx.db, ctx.db,
input.cardId, input.cardId,
); );
if (!card) return; if (!card || !card.list)
throw new TRPCError({
message: `Card with public ID ${input.cardId} not found`,
code: "NOT_FOUND",
});
const currentList = card.list; const currentList = card.list;
const currentIndex = card.index; const currentIndex = card.index;
@@ -254,7 +319,11 @@ export const cardRouter = createTRPCRouter({
input.newListId, input.newListId,
); );
if (!newList) return; if (!newList)
throw new TRPCError({
message: `List with public ID ${input.newListId} not found`,
code: "NOT_FOUND",
});
if (newIndex === undefined) { if (newIndex === undefined) {
const lastCardIndex = newList.cards.length const lastCardIndex = newList.cards.length
@@ -264,8 +333,6 @@ export const cardRouter = createTRPCRouter({
newIndex = lastCardIndex !== undefined ? lastCardIndex + 1 : 0; newIndex = lastCardIndex !== undefined ? lastCardIndex + 1 : 0;
} }
if (!currentList?.id || !newList.id) return;
const result = await cardRepo.reorder(ctx.db, { const result = await cardRepo.reorder(ctx.db, {
currentListId: currentList.id, currentListId: currentList.id,
newListId: newList.id, newListId: newList.id,

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { generateUID } from "~/utils/generateUID"; import { generateUID } from "~/utils/generateUID";
@@ -89,7 +90,11 @@ export const importRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const newImport = await importRepo.create(ctx.db, { const newImport = await importRepo.create(ctx.db, {
source: "trello", source: "trello",
@@ -105,7 +110,11 @@ export const importRouter = createTRPCRouter({
input.workspacePublicId, input.workspacePublicId,
); );
if (!workspace) return; if (!workspace)
throw new TRPCError({
message: `Workspace with public ID ${input.workspacePublicId} not found`,
code: "NOT_FOUND",
});
for (const boardId of input.boardIds) { for (const boardId of input.boardIds) {
const response = await fetch( const response = await fetch(
@@ -135,7 +144,11 @@ export const importRouter = createTRPCRouter({
const newBoardId = newBoard?.id; const newBoardId = newBoard?.id;
if (!newBoardId) return; if (!newBoardId)
throw new TRPCError({
message: "Failed to create new board",
code: "INTERNAL_SERVER_ERROR",
});
let listIndex = 0; let listIndex = 0;

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
@@ -17,14 +18,22 @@ export const labelRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const card = await cardRepo.getCardWithListByPublicId( const card = await cardRepo.getCardWithListByPublicId(
ctx.db, ctx.db,
input.cardPublicId, input.cardPublicId,
); );
if (!card?.list) return; if (!card?.list)
throw new TRPCError({
message: `Card with public ID ${input.cardPublicId} not found`,
code: "NOT_FOUND",
});
const result = await labelRepo.create(ctx.db, { const result = await labelRepo.create(ctx.db, {
name: input.name, name: input.name,

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
@@ -17,14 +18,22 @@ export const listRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const board = await boardRepo.getWithLatestListIndexByPublicId( const board = await boardRepo.getWithLatestListIndexByPublicId(
ctx.db, ctx.db,
input.boardPublicId, input.boardPublicId,
); );
if (!board) return; if (!board)
throw new TRPCError({
message: `Board with public ID ${input.boardPublicId} not found`,
code: "NOT_FOUND",
});
const latestListIndex = board.lists[0]?.index; const latestListIndex = board.lists[0]?.index;
@@ -49,7 +58,11 @@ export const listRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const list = await listRepo.getByPublicId(ctx.db, input.listId); const list = await listRepo.getByPublicId(ctx.db, input.listId);
if (!list) return; if (!list)
throw new TRPCError({
message: `List with public ID ${input.listId} not found`,
code: "NOT_FOUND",
});
const result = listRepo.reorder(ctx.db, { const result = listRepo.reorder(ctx.db, {
boardPublicId: list.boardId, boardPublicId: list.boardId,
@@ -69,9 +82,19 @@ export const listRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const list = await listRepo.getByPublicId(ctx.db, input.listPublicId); const list = await listRepo.getByPublicId(ctx.db, input.listPublicId);
if (!list || !userId) return; if (!list)
throw new TRPCError({
message: `List with public ID ${input.listPublicId} not found`,
code: "NOT_FOUND",
});
const deletedAt = new Date().toISOString(); const deletedAt = new Date().toISOString();

View File

@@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { TRPCError } from "@trpc/server";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc"; import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import * as workspaceRepo from "~/server/db/repository/workspace.repo"; import * as workspaceRepo from "~/server/db/repository/workspace.repo";
@@ -7,7 +8,11 @@ export const workspaceRouter = createTRPCRouter({
all: protectedProcedure.query(async ({ ctx }) => { all: protectedProcedure.query(async ({ ctx }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const result = await workspaceRepo.getAllByUserId(ctx.db, userId); const result = await workspaceRepo.getAllByUserId(ctx.db, userId);
@@ -32,7 +37,11 @@ export const workspaceRouter = createTRPCRouter({
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id; const userId = ctx.user?.id;
if (!userId) return; if (!userId)
throw new TRPCError({
message: `User not authenticated`,
code: "UNAUTHORIZED",
});
const result = await workspaceRepo.create(ctx.db, { const result = await workspaceRepo.create(ctx.db, {
name: input.name, name: input.name,