Skip to content

Commit

Permalink
schema
Browse files Browse the repository at this point in the history
  • Loading branch information
sinamics committed Sep 1, 2024
1 parent 4851f5c commit 12f9aff
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 43 deletions.
19 changes: 5 additions & 14 deletions src/pages/api/v1/network/[id]/member/[memberId]/_schema.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
import { z } from "zod";

// Schema for updateable fields
export const updateableFieldsSchema = z
// Schema for updateable fields metadata
export const updateableFieldsMetaSchema = z
.object({
name: z.object({
type: z.literal("string"),
destinations: z.array(z.literal("database")),
}),
authorized: z.object({
type: z.literal("boolean"),
destinations: z.array(z.literal("controller")),
}),
name: z.string().optional(),
authorized: z.boolean().optional(),
})
.strict();

// Schema for the request body
export const updateMemberBodySchema = z.record(z.union([z.string(), z.boolean()]));

// Schema for the context passed to the handler
export const handlerContextSchema = z.object({
body: updateMemberBodySchema,
body: z.record(z.unknown()),
userId: z.string(),
networkId: z.string(),
memberId: z.string(),
Expand Down
42 changes: 13 additions & 29 deletions src/pages/api/v1/network/[id]/member/[memberId]/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import * as ztController from "~/utils/ztApi";
import {
deleteHandlerContextSchema,
handlerContextSchema,
updateableFieldsSchema,
updateableFieldsMetaSchema,
} from "./_schema";

// Number of allowed requests per minute
Expand All @@ -20,20 +20,6 @@ const limiter = rateLimit({

const REQUEST_PR_MINUTE = 50;

// Function to parse and validate fields based on the expected type
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
const parseField = (key: string, value: any, expectedType: string) => {
if (expectedType === "string") {
return value; // Assume all strings are valid
}
if (expectedType === "boolean") {
if (value === "true" || value === "false") {
return value === "true";
}
throw new Error(`Field '${key}' expected to be boolean, got: ${value}`);
}
};

export default async function apiNetworkUpdateMembersHandler(
req: NextApiRequest,
res: NextApiResponse,
Expand Down Expand Up @@ -75,37 +61,35 @@ const POST_updateNetworkMember = SecuredPrivateApiRoute(
const validatedContext = handlerContextSchema.parse(context);
const { body, userId, networkId, memberId, ctx } = validatedContext;

// Validate the input data
const validatedInput = updateableFieldsMetaSchema.parse(body);

const updateableFields = {
name: { type: "string", destinations: ["controller", "database"] },
authorized: { type: "boolean", destinations: ["controller"] },
};

if (Object.keys(body).length === 0) {
return res.status(400).json({ error: "No data provided for update" });
}

const updateableFields = updateableFieldsSchema.parse({
name: { type: "string", destinations: ["database"] },
authorized: { type: "boolean", destinations: ["controller"] },
});

const databasePayload: Partial<network_members> = {};
const controllerPayload: Partial<network_members> = {};

// Iterate over keys in the request body
for (const key in body) {
// Check if the key is not in updateableFields
if (!(key in updateableFields)) {
return res.status(400).json({ error: `Invalid field: ${key}` });
}

for (const [key, value] of Object.entries(validatedInput)) {
try {
const parsedValue = parseField(key, body[key], updateableFields[key].type);
if (updateableFields[key].destinations.includes("database")) {
databasePayload[key] = parsedValue;
databasePayload[key] = value;
}
if (updateableFields[key].destinations.includes("controller")) {
controllerPayload[key] = parsedValue;
controllerPayload[key] = value;
}
} catch (error) {
return res.status(400).json({ error: error.message });
}
}

try {
// make sure the member is valid
const network = await prisma.network.findUnique({
Expand Down

0 comments on commit 12f9aff

Please sign in to comment.