Merge pull request #13 from calcom/feat/swagger-docs

pull/9078/head
Agusti Fernandez 2022-03-30 17:07:00 +02:00 committed by GitHub
commit 064c39b7f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 406 additions and 178 deletions

View File

@ -8,7 +8,8 @@ export const captureErrors: NextMiddleware = async (_req, res, next) => {
await next();
} catch (err) {
Sentry.captureException(err);
res.status(500);
res.json({ error: err });
console.log(err);
res.status(400).json({ message: "Something went wrong", error: err });
// res.json({ error: err });
}
};

View File

@ -11,13 +11,14 @@ const dateInPast = function (firstDate: Date, secondDate: Date) {
const today = new Date();
export const verifyApiKey: NextMiddleware = async (req, res, next) => {
if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" });
const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } });
if (!apiKey) {
res.status(400).json({ error: "Your api key is not valid" });
res.status(401).json({ error: "Your api key is not valid" });
throw new Error("No api key found");
}
if (apiKey.expiresAt && apiKey.userId && dateInPast(apiKey.expiresAt, today)) {
res.setHeader("Calcom-User-ID", apiKey.userId);
await next();
} else res.status(400).json({ error: "Your api key is not valid" });
} else res.status(401).json({ error: "Your api key is not valid" });
};

View File

@ -1,4 +1,4 @@
import { User, ApiKey } from "@calcom/prisma/client";
import { User, ApiKey, Team, SelectedCalendar } from "@calcom/prisma/client";
// Base response, used for all responses
export type BaseResponse = {
@ -20,3 +20,19 @@ export type ApiKeyResponse = BaseResponse & {
export type ApiKeysResponse = BaseResponse & {
data?: Partial<ApiKey>[];
};
// API Key
export type TeamResponse = BaseResponse & {
data?: Partial<Team>;
};
export type TeamsResponse = BaseResponse & {
data?: Partial<Team>[];
};
// API Key
export type SelectedCalendarResponse = BaseResponse & {
data?: Partial<SelectedCalendar>;
};
export type SelectedCalendarsResponse = BaseResponse & {
data?: Partial<SelectedCalendar>[];
};

View File

@ -1,11 +1,13 @@
import { withValidation } from "next-validations";
import { z } from "zod";
const schemaSelectedCalendar = z.object({}).strict();
const withValidSelectedCalendar = withValidation({
schema: schemaSelectedCalendar,
import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod";
export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({});
export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true });
export const withValidSelectedCalendar = withValidation({
schema: schemaSelectedCalendarBodyParams,
type: "Zod",
mode: "body",
});
export { schemaSelectedCalendar, withValidSelectedCalendar };

View File

@ -6,7 +6,7 @@ export const baseApiParams = z
.object({
// since we added apiKey as query param this is required by next-validations helper
// for query params to work properly and not fail.
apiKey: z.string().cuid(),
apiKey: z.string().cuid().optional(),
// version required for supporting /v1/ redirect to query in api as *?version=1
version: z.string().optional(),
})

View File

@ -1,19 +1,13 @@
import { withValidation } from "next-validations";
import { z } from "zod";
const schemaTeam = z
.object({
slug: z.string().min(3),
name: z.string().min(3),
hideBranding: z.boolean().default(false),
bio: z.string().min(3).optional(),
logo: z.string().optional(),
})
.strict();
const withValidTeam = withValidation({
schema: schemaTeam,
import { _TeamModel as Team } from "@calcom/prisma/zod";
export const schemaTeamBodyParams = Team.omit({ id: true });
export const schemaTeamPublic = Team.omit({});
export const withValidTeam = withValidation({
schema: schemaTeamBodyParams,
type: "Zod",
mode: "body",
});
export { schemaTeam, withValidTeam };

View File

@ -28,12 +28,14 @@
"babel-jest": "^27.5.1",
"husky": "^7.0.4",
"jest": "^27.5.1",
"node-mocks-http": "^1.11.0"
"node-mocks-http": "^1.11.0",
"prettier": "^2.6.1"
},
"dependencies": {
"@sentry/nextjs": "^6.19.2",
"next": "^12.1.0",
"next-api-middleware": "^1.0.1",
"next-swagger-doc": "^0.2.1",
"next-transpile-modules": "^9.0.0",
"next-validations": "^0.1.11",
"typescript": "^4.6.3",

View File

@ -1,17 +1,22 @@
// import { NextApiResponse } from "next";
import { NextRequest, NextResponse } from "next/server";
// Not much useful yet as prisma.client can't be used in the middlewares (client is not available)
// For now we just throw early if no apiKey is passed,
// but we could also check if the apiKey is valid if we had prisma here.
export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) {
export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest, res: NextResponse) {
const response = NextResponse.next();
const apiKey = nextUrl.searchParams.get("apiKey");
if (apiKey) return response;
// if no apiKey is passed, we throw early
// if no apiKey is passed, we throw early a 401 unauthorized
else
throw new Error(
"You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=<your-api-key>"
new NextResponse(
JSON.stringify({
message:
"You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=<your-api-key>",
}),
{ status: 401, statusText: "Unauthorized" }
);
}

13
pages/api/docs.ts Normal file
View File

@ -0,0 +1,13 @@
import { withSwagger } from "next-swagger-doc";
const swaggerHandler = withSwagger({
definition: {
openapi: "3.0.0",
info: {
title: "Cal.com Public API",
version: "1.0.0",
},
},
apiFolder: "pages/api",
});
export default swaggerHandler();

View File

@ -2,28 +2,41 @@ import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { BaseResponse } from "@lib/types";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
type ResponseData = {
message?: string;
error?: unknown;
};
/**
* @swagger
* /api/selectedCalendars/:id/delete:
* delete:
* description: Remove an existing selectedCalendar
* responses:
* 201:
* description: OK, selectedCalendar removed successfuly
* model: SelectedCalendar
* 400:
* description: Bad request. SelectedCalendar id is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse<BaseResponse>) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query", safe.error);
export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, method } = req;
const safe = await schemaQueryIdParseInt.safeParse(query);
if (method === "DELETE" && safe.success && safe.data) {
const selectedCalendar = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } });
// We only remove the selectedCalendar type from the database if there's an existing resource.
if (selectedCalendar)
res.status(200).json({ message: `selectedCalendar with id: ${safe.data.id} deleted successfully` });
// This catches the error thrown by prisma.selectedCalendar.delete() if the resource is not found.
else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` });
// Reject any other HTTP method than POST
} else res.status(405).json({ message: "Only DELETE Method allowed" });
const data = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } });
if (data)
res.status(200).json({ message: `SelectedCalendar with id: ${safe.data.id} deleted successfully` });
else
(error: Error) =>
res.status(400).json({
message: `SelectedCalendar with id: ${safe.data.id} was not able to be processed`,
error,
});
}
export default withValidQueryIdTransformParseInt(deleteSelectedCalendar);
export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSelectedCalendar));

View File

@ -1,38 +1,56 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { SelectedCalendar } from "@calcom/prisma/client";
import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { SelectedCalendarResponse } from "@lib/types";
import {
schemaSelectedCalendarBodyParams,
schemaSelectedCalendarPublic,
withValidSelectedCalendar,
} from "@lib/validations/selected-calendar";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
type ResponseData = {
data?: SelectedCalendar;
message?: string;
error?: unknown;
};
/**
* @swagger
* /api/selectedCalendars/:id/edit:
* patch:
* description: Edits an existing selectedCalendar
* responses:
* 201:
* description: OK, selectedCalendar edited successfuly
* model: SelectedCalendar
* 400:
* description: Bad request. SelectedCalendar body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function editSelectedCalendar(
req: NextApiRequest,
res: NextApiResponse<SelectedCalendarResponse>
) {
const safeQuery = await schemaQueryIdParseInt.safeParse(req.query);
const safeBody = await schemaSelectedCalendarBodyParams.safeParse(req.body);
export async function editSelectedCalendar(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, body, method } = req;
const safeQuery = await schemaQueryIdParseInt.safeParse(query);
const safeBody = await schemaSelectedCalendar.safeParse(body);
if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request");
const selectedCalendar = await prisma.selectedCalendar.update({
where: { id: safeQuery.data.id },
data: safeBody.data,
});
const data = schemaSelectedCalendarPublic.parse(selectedCalendar);
if (method === "PATCH" && safeQuery.success && safeBody.success) {
const data = await prisma.selectedCalendar.update({
where: { id: safeQuery.data.id },
data: safeBody.data,
});
if (data) res.status(200).json({ data });
else
res
.status(404)
.json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error });
// Reject any other HTTP method than POST
} else res.status(405).json({ message: "Only PATCH Method allowed for updating selectedCalendars" });
if (data) res.status(200).json({ data });
else
(error: Error) =>
res.status(404).json({
message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`,
error,
});
}
export default withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar));
export default withMiddleware("HTTP_PATCH")(
withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar))
);

View File

@ -1,29 +1,45 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { SelectedCalendar } from "@calcom/prisma/client";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { SelectedCalendarResponse } from "@lib/types";
import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
type ResponseData = {
data?: SelectedCalendar;
message?: string;
error?: unknown;
};
/**
* @swagger
* /api/selectedCalendars/:id:
* get:
* description: find selectedCalendar by ID
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: SelectedCalendar was not found
*/
export async function selectedCalendarById(
req: NextApiRequest,
res: NextApiResponse<SelectedCalendarResponse>
) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query");
export async function selectedCalendar(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { query, method } = req;
const safe = await schemaQueryIdParseInt.safeParse(query);
if (method === "GET" && safe.success) {
const data = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } });
const selectedCalendar = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } });
const data = schemaSelectedCalendarPublic.parse(selectedCalendar);
if (data) res.status(200).json({ data });
else res.status(404).json({ message: "Event type not found" });
// Reject any other HTTP method than POST
} else res.status(405).json({ message: "Only GET Method allowed" });
if (selectedCalendar) res.status(200).json({ data });
else
(error: Error) =>
res.status(404).json({
message: "SelectedCalendar was not found",
error,
});
}
export default withValidQueryIdTransformParseInt(selectedCalendar);
export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(selectedCalendarById));

View File

@ -1,15 +1,37 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { SelectedCalendar } from "@calcom/prisma/client";
type ResponseData = {
data?: SelectedCalendar[];
error?: unknown;
};
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { SelectedCalendarsResponse } from "@lib/types";
import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar";
/**
* @swagger
* /api/selectedCalendars:
* get:
* description: Returns all selected calendars
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: No selectedCalendars were found
*/
async function allSelectedCalendars(_: NextApiRequest, res: NextApiResponse<SelectedCalendarsResponse>) {
const selectedCalendars = await prisma.selectedCalendar.findMany();
const data = selectedCalendars.map((selectedCalendar) =>
schemaSelectedCalendarPublic.parse(selectedCalendar)
);
export default async function selectedCalendar(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const data = await prisma.selectedCalendar.findMany();
if (data) res.status(200).json({ data });
else res.status(400).json({ error: "No data found" });
else
(error: Error) =>
res.status(404).json({
message: "No SelectedCalendars were found",
error,
});
}
export default withMiddleware("HTTP_GET")(allSelectedCalendars);

View File

@ -1,28 +1,43 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { SelectedCalendar } from "@calcom/prisma/client";
import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { SelectedCalendarResponse } from "@lib/types";
import {
schemaSelectedCalendarBodyParams,
schemaSelectedCalendarPublic,
withValidSelectedCalendar,
} from "@lib/validations/selected-calendar";
type ResponseData = {
data?: SelectedCalendar;
message?: string;
error?: string;
};
/**
* @swagger
* /api/selectedCalendars/new:
* post:
* description: Creates a new selected calendar
* responses:
* 201:
* description: OK, selected calendar created
* model: SelectedCalendar
* 400:
* description: Bad request. SelectedCalendar body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse<SelectedCalendarResponse>) {
const safe = schemaSelectedCalendarBodyParams.safeParse(req.body);
if (!safe.success) throw new Error("Invalid request body", safe.error);
async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const { body, method } = req;
const safe = schemaSelectedCalendar.safeParse(body);
if (method === "POST" && safe.success) {
await prisma.selectedCalendar
.create({ data: safe.data })
.then((data) => res.status(201).json({ data }))
.catch((error) =>
res.status(400).json({ message: "Could not create selectedCalendar type", error: error })
);
// Reject any other HTTP method than POST
} else res.status(405).json({ error: "Only POST Method allowed" });
const selectedCalendar = await prisma.selectedCalendar.create({ data: safe.data });
const data = schemaSelectedCalendarPublic.parse(selectedCalendar);
if (data) res.status(201).json({ data, message: "SelectedCalendar created successfully" });
else
(error: Error) =>
res.status(400).json({
message: "Could not create new selectedCalendar",
error,
});
}
export default withValidSelectedCalendar(createSelectedCalendar);
export default withMiddleware("HTTP_POST")(withValidSelectedCalendar(createSelectedCalendar));

View File

@ -3,19 +3,29 @@ import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { BaseResponse } from "@lib/types";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
type ResponseData = {
message: string;
error?: object;
};
export async function deleteTeam(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
/**
* @swagger
* /api/teams/:id/delete:
* delete:
* description: Remove an existing team
* responses:
* 201:
* description: OK, team removed successfuly
* model: Team
* 400:
* description: Bad request. Team id is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function deleteTeam(req: NextApiRequest, res: NextApiResponse<BaseResponse>) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query");
if (!safe.success) throw new Error("Invalid request query", safe.error);
const data = await prisma.team.delete({ where: { id: safe.data.id } });
@ -28,4 +38,4 @@ export async function deleteTeam(req: NextApiRequest, res: NextApiResponse<Respo
});
}
export default withMiddleware("HTTP_DELETE", "addRequestId")(withValidQueryIdTransformParseInt(deleteTeam));
export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteTeam));

View File

@ -1,30 +1,39 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { Team } from "@calcom/prisma/client";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { TeamResponse } from "@lib/types";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
import { schemaTeam, withValidTeam } from "@lib/validations/team";
import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team";
type ResponseData = {
data?: Team;
message?: string;
error?: object;
};
export async function editTeam(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
/**
* @swagger
* /api/teams/:id/edit:
* patch:
* description: Edits an existing team
* responses:
* 201:
* description: OK, team edited successfuly
* model: Team
* 400:
* description: Bad request. Team body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function editTeam(req: NextApiRequest, res: NextApiResponse<TeamResponse>) {
const safeQuery = await schemaQueryIdParseInt.safeParse(req.query);
const safeBody = await schemaTeam.safeParse(req.body);
const safeBody = await schemaTeamBodyParams.safeParse(req.body);
if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request");
const data = await prisma.team.update({
const team = await prisma.team.update({
where: { id: safeQuery.data.id },
data: safeBody.data,
});
const data = schemaTeamPublic.parse(team);
if (data) res.status(200).json({ data });
else
@ -35,7 +44,4 @@ export async function editTeam(req: NextApiRequest, res: NextApiResponse<Respons
});
}
export default withMiddleware(
"HTTP_PATCH",
"addRequestId"
)(withValidQueryIdTransformParseInt(withValidTeam(editTeam)));
export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidTeam(editTeam)));

View File

@ -1,27 +1,36 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { Team } from "@calcom/prisma/client";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { TeamResponse } from "@lib/types";
import {
schemaQueryIdParseInt,
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
import { schemaTeamPublic } from "@lib/validations/team";
type ResponseData = {
data?: Team;
message?: string;
error?: object;
};
export async function teamById(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
/**
* @swagger
* /api/teams/:id:
* get:
* description: find team by ID
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: Team was not found
*/
export async function teamById(req: NextApiRequest, res: NextApiResponse<TeamResponse>) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query");
const data = await prisma.team.findUnique({ where: { id: safe.data.id } });
const team = await prisma.team.findUnique({ where: { id: safe.data.id } });
const data = schemaTeamPublic.parse(team);
if (data) res.status(200).json({ data });
if (team) res.status(200).json({ data });
else
(error: Error) =>
res.status(404).json({

View File

@ -1,23 +1,32 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { Team } from "@calcom/prisma/client";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { TeamsResponse } from "@lib/types";
import { schemaTeamPublic } from "@lib/validations/team";
type ResponseData = {
data?: Team[];
message?: string;
error?: object;
};
async function allTeams(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const data = await prisma.team.findMany();
/**
* @swagger
* /api/teams:
* get:
* description: Returns all teams
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: No teams were found
*/
async function allTeams(_: NextApiRequest, res: NextApiResponse<TeamsResponse>) {
const teams = await prisma.team.findMany();
const data = teams.map((team) => schemaTeamPublic.parse(team));
if (data) res.status(200).json({ data });
else
(error: Error) =>
res.status(400).json({
res.status(404).json({
message: "No Teams were found",
error,
});

View File

@ -1,31 +1,39 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { Team } from "@calcom/prisma/client";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { schemaTeam, withValidTeam } from "@lib/validations/team";
import type { TeamResponse } from "@lib/types";
import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team";
type ResponseData = {
data?: Team;
error?: object;
};
/**
* @swagger
* /api/teams/new:
* post:
* description: Creates a new team
* responses:
* 201:
* description: OK, team created
* model: Team
* 400:
* description: Bad request. Team body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
async function createTeam(req: NextApiRequest, res: NextApiResponse<TeamResponse>) {
const safe = schemaTeamBodyParams.safeParse(req.body);
if (!safe.success) throw new Error("Invalid request body", safe.error);
async function createTeam(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
const safe = schemaTeam.safeParse(req.body);
if (!safe.success) throw new Error("Invalid request body");
const team = await prisma.team.create({ data: safe.data });
const data = schemaTeamPublic.parse(team);
const data = await prisma.team.create({ data: safe.data });
if (data) res.status(201).json({ data });
if (data) res.status(201).json({ data, message: "Team created successfully" });
else
(error: Error) =>
res.status(400).json({
error: {
message: "Could not create new team",
error,
},
message: "Could not create new team",
error,
});
}
export default withMiddleware("addRequestId", "HTTP_POST")(withValidTeam(createTeam));
export default withMiddleware("HTTP_POST")(withValidTeam(createTeam));

View File

@ -9,6 +9,20 @@ import {
withValidQueryIdTransformParseInt,
} from "@lib/validations/shared/queryIdTransformParseInt";
/**
* @swagger
* /api/users/:id/delete:
* delete:
* description: Remove an existing user
* responses:
* 201:
* description: OK, user removed successfuly
* model: User
* 400:
* description: Bad request. User id is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function deleteUser(req: NextApiRequest, res: NextApiResponse<BaseResponse>) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query", safe.error);

View File

@ -10,6 +10,20 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user";
/**
* @swagger
* /api/users/:id/edit:
* patch:
* description: Edits an existing user
* responses:
* 201:
* description: OK, user edited successfuly
* model: User
* 400:
* description: Bad request. User body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
export async function editUser(req: NextApiRequest, res: NextApiResponse<UserResponse>) {
const safeQuery = await schemaQueryIdParseInt.safeParse(req.query);
const safeBody = await schemaUserBodyParams.safeParse(req.body);

View File

@ -10,6 +10,19 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
import { schemaUserPublic } from "@lib/validations/user";
/**
* @swagger
* /api/users/:id:
* get:
* description: find user by ID
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: User was not found
*/
export async function userById(req: NextApiRequest, res: NextApiResponse<UserResponse>) {
const safe = await schemaQueryIdParseInt.safeParse(req.query);
if (!safe.success) throw new Error("Invalid request query");

View File

@ -6,6 +6,19 @@ import { withMiddleware } from "@lib/helpers/withMiddleware";
import { UsersResponse } from "@lib/types";
import { schemaUserPublic } from "@lib/validations/user";
/**
* @swagger
* /api/users:
* get:
* description: Returns all users
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 404:
* description: No users were found
*/
async function allUsers(_: NextApiRequest, res: NextApiResponse<UsersResponse>) {
const users = await prisma.user.findMany();
const data = users.map((user) => schemaUserPublic.parse(user));
@ -13,7 +26,7 @@ async function allUsers(_: NextApiRequest, res: NextApiResponse<UsersResponse>)
if (data) res.status(200).json({ data });
else
(error: Error) =>
res.status(400).json({
res.status(404).json({
message: "No Users were found",
error,
});

View File

@ -6,6 +6,20 @@ import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { UserResponse } from "@lib/types";
import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user";
/**
* @swagger
* /api/users/new:
* post:
* description: Creates a new user
* responses:
* 201:
* description: OK, user created
* model: User
* 400:
* description: Bad request. User body is invalid.
* 401:
* description: Authorization information is missing or invalid.
*/
async function createUser(req: NextApiRequest, res: NextApiResponse<UserResponse>) {
const safe = schemaUserBodyParams.safeParse(req.body);
if (!safe.success) throw new Error("Invalid request body", safe.error);