feat: adds module transpiling so api can require @calcom/prisma and not @prisma/client directly

This commit is contained in:
Agusti Fernandez Pardo
2022-03-25 19:37:51 +01:00
parent a2817a2fee
commit c2234593db
10 changed files with 183 additions and 3 deletions
+3
View File
@@ -39,3 +39,6 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished
Since this will only support an API, we redirect the requests to root to the /api folder.
We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=*
The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc
+16
View File
@@ -0,0 +1,16 @@
import { withValidation } from "next-validations";
import { z } from "zod";
const schemaApiKey = z
.object({
expiresAt: z.date().optional(), // default is 30 days
note: z.string().min(1).optional(),
})
.strict(); // Adding strict so that we can disallow passing in extra fields
const withValidApiKey = withValidation({
schema: schemaApiKey,
type: "Zod",
mode: "body",
});
export { schemaApiKey, withValidApiKey };
+7 -2
View File
@@ -1,4 +1,9 @@
module.exports = {
const withTM = require("next-transpile-modules")([
"@calcom/prisma",
]);
module.exports = withTM({
async rewrites() {
return [
// This redirects requests recieved at / the root to the /api/ folder.
@@ -13,4 +18,4 @@ module.exports = {
},
];
},
};
});
+2 -1
View File
@@ -31,9 +31,10 @@
"node-mocks-http": "^1.11.0"
},
"dependencies": {
"typescript": "^4.6.3",
"next": "^12.1.0",
"next-transpile-modules": "^9.0.0",
"next-validations": "^0.1.11",
"typescript": "^4.6.3",
"zod": "^3.14.2"
}
}
+36
View File
@@ -0,0 +1,36 @@
import { PrismaClient } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt";
const prisma = new PrismaClient();
type ResponseData = {
message?: string;
error?: unknown;
};
export async function eventType(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, method } = req;
const safe = await schemaQueryId.safeParse(query);
if (safe.success) {
if (method === "DELETE") {
// DELETE WILL DELETE THE EVENT TYPE
prisma.eventType
.delete({ where: { id: safe.data.id } })
.then(() => {
// We only remove the event type from the database if there's an existing resource.
res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` });
})
.catch((error) => {
// This catches the error thrown by prisma.eventType.delete() if the resource is not found.
res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error });
});
} else {
// Reject any other HTTP method than POST
res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" });
}
}
}
export default withValidQueryId(eventType);
+37
View File
@@ -0,0 +1,37 @@
import { PrismaClient, EventType } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { schemaEventType, withValidEventType } from "@lib/validations/eventType";
import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt";
const prisma = new PrismaClient();
type ResponseData = {
data?: EventType;
message?: string;
error?: unknown;
};
export async function editEventType(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, body, method } = req;
const safeQuery = await schemaQueryId.safeParse(query);
const safeBody = await schemaEventType.safeParse(body);
if (method === "PATCH") {
if (safeQuery.success && safeBody.success) {
await prisma.eventType.update({
where: { id: safeQuery.data.id },
data: safeBody.data,
}).then(event => {
res.status(200).json({ data: event });
}).catch(error => {
res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error })
});
}
} else {
// Reject any other HTTP method than POST
res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" });
}
}
export default withValidQueryId(withValidEventType(editEventType));
+31
View File
@@ -0,0 +1,31 @@
import { PrismaClient, EventType } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt";
const prisma = new PrismaClient();
type ResponseData = {
data?: EventType;
message?: string;
error?: unknown;
};
export async function eventType(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, method } = req;
const safe = await schemaQueryId.safeParse(query);
if (safe.success) {
if (method === "GET") {
const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } });
if (event) res.status(200).json({ data: event });
if (!event) res.status(404).json({ message: "Event type not found" });
} else {
// Reject any other HTTP method than POST
res.status(405).json({ message: "Only GET Method allowed" });
}
}
}
export default withValidQueryId(eventType);
+19
View File
@@ -0,0 +1,19 @@
import { PrismaClient, ApiKey } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
const prisma = new PrismaClient();
type ResponseData = {
data?: ApiKey[];
error?: unknown;
};
export default async function apiKey(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
try {
const apiKeys = await prisma.apiKey.findMany({ where: { id: `${req.query.eventTypeId}` } });
res.status(200).json({ data: { ...apiKeys } });
} catch (error) {
console.log(error);
// FIXME: Add zod for validation/error handling
res.status(400).json({ error: error });
}
}
+30
View File
@@ -0,0 +1,30 @@
import { PrismaClient, ApiKey } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey";
const prisma = new PrismaClient();
type ResponseData = {
data?: ApiKey;
message?: string;
error?: string;
};
async function createApiKey(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { body, method } = req;
if (method === "POST") {
const safe = schemaApiKey.safeParse(body);
if (safe.success && safe.data) {
await prisma.apiKey
.create({ data: { ...safe.data, user: { connect: { id: 1 } }
}})
.then((event) => res.status(201).json({ data: event }))
.catch((error) => res.status(400).json({ message: "Could not create event type", error: error }));
}
} else {
// Reject any other HTTP method than POST
res.status(405).json({ error: "Only POST Method allowed" });
}
}
export default withValidApiKey(createApiKey);
+2
View File
@@ -21,7 +21,9 @@
"jsx": "preserve",
"paths": {
"@api/*": ["pages/api/*"],
"@prisma/client/*": ["@calcom/prisma/client/*"],
"@lib/*": ["lib/*"]
},
},
"include": [