Skip to content

Commit a724f9c

Browse files
committed
add docs
1 parent 654bc40 commit a724f9c

File tree

5 files changed

+150
-20
lines changed

5 files changed

+150
-20
lines changed

src/api/components/index.ts

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,6 @@ export const acmCoreOrganization = z
2828
examples: ["ACM", "Infrastructure Committee"],
2929
});
3030

31-
export function withTags<T extends FastifyZodOpenApiSchema>(
32-
tags: string[],
33-
schema: T,
34-
) {
35-
return {
36-
tags,
37-
...schema,
38-
};
39-
}
40-
4131
export type RoleSchema = {
4232
"x-required-roles": AppRoles[];
4333
"x-disable-api-key-auth": boolean;
@@ -48,6 +38,60 @@ type RolesConfig = {
4838
disableApiKeyAuth: boolean;
4939
};
5040

41+
export const notAuthenticatedError = z
42+
.object({
43+
name: z.literal("UnauthenticatedError"),
44+
id: z.literal(102),
45+
message: z.string().min(1),
46+
})
47+
.meta({
48+
id: "notAuthenticatedError",
49+
description: "Request not authenticated.",
50+
});
51+
52+
export const notFoundError = z
53+
.object({
54+
name: z.literal("NotFoundError"),
55+
id: z.literal(103),
56+
message: z.string().min(1),
57+
})
58+
.meta({
59+
id: "notFoundError",
60+
description: "Resource was not found.",
61+
example: {
62+
name: "NotFoundError",
63+
id: 103,
64+
message: "{url} is not a valid URL.",
65+
},
66+
});
67+
68+
export const notAuthorizedError = z
69+
.object({
70+
name: z.literal("UnauthorizedError"),
71+
id: z.literal(101),
72+
message: z.string().min(1),
73+
})
74+
.meta({
75+
id: "notAuthorizedError",
76+
description: "Request not authorized (lacking permissions).",
77+
});
78+
79+
export const internalServerError = z
80+
.object({
81+
name: z.literal("InternalServerError"),
82+
id: z.literal(100),
83+
message: z
84+
.string()
85+
.min(1)
86+
.default(
87+
"An internal server error occurred. Please try again or contact support.",
88+
),
89+
})
90+
.meta({
91+
id: "internalServerError",
92+
description: "The server encountered an error processing the request.",
93+
});
94+
5195
export function withRoles<T extends FastifyZodOpenApiSchema>(
5296
roles: AppRoles[],
5397
schema: T,
@@ -57,6 +101,11 @@ export function withRoles<T extends FastifyZodOpenApiSchema>(
57101
if (!disableApiKeyAuth) {
58102
security.push({ apiKeyAuth: [] });
59103
}
104+
const responses = {
105+
401: notAuthorizedError,
106+
403: notAuthenticatedError,
107+
...schema.response,
108+
};
60109
return {
61110
security,
62111
"x-required-roles": roles,
@@ -66,5 +115,22 @@ export function withRoles<T extends FastifyZodOpenApiSchema>(
66115
? `${disableApiKeyAuth ? "API key authentication is not permitted for this route.\n\n" : ""}Requires one of the following roles: ${roles.join(", ")}.${schema.description ? `\n\n${schema.description}` : ""}`
67116
: "Requires valid authentication but no specific role.",
68117
...schema,
118+
response: responses,
119+
};
120+
}
121+
122+
export function withTags<T extends FastifyZodOpenApiSchema>(
123+
tags: string[],
124+
schema: T,
125+
) {
126+
const responses = {
127+
200: z.object({}),
128+
500: internalServerError,
129+
...schema.response,
130+
};
131+
return {
132+
tags,
133+
...schema,
134+
response: responses,
69135
};
70136
}

src/api/createLambdaPackage.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ export const packagesToTransfer = [
1515
"passkit-generator",
1616
"argon2",
1717
"ioredis",
18+
"fastify-zod-openapi",
19+
"@fastify/swagger",
20+
"zod-openapi",
21+
"zod",
1822
];
1923
const filePath = `${getPath().dirname}/package.json`;
2024
const writeFilePath = `${getPath().dirname}/package.lambda.json`;

src/api/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,10 @@
5959
"stripe": "^18.0.0",
6060
"uuid": "^11.1.0",
6161
"zod": "^3.25.73",
62-
"zod-validation-error": "^3.3.1"
62+
"zod-validation-error": "^3.3.1",
63+
"@fastify/swagger": "^9.5.0"
6364
},
6465
"devDependencies": {
65-
"@fastify/swagger": "^9.5.0",
6666
"@fastify/swagger-ui": "^5.2.2",
6767
"@tsconfig/node22": "^22.0.1",
6868
"@types/aws-lambda": "^8.10.149",

src/api/routes/events.ts

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import {
4040
} from "fastify-zod-openapi";
4141
import {
4242
acmCoreOrganization,
43+
notFoundError,
4344
ts,
4445
withRoles,
4546
withTags,
@@ -178,7 +179,16 @@ const eventsPlugin: FastifyPluginAsyncZodOpenApi = async (
178179
includeMetadata: zodIncludeMetadata,
179180
}),
180181
summary: "Retrieve calendar events with applied filters.",
181-
// response: { 200: getEventsSchema },
182+
response: {
183+
200: {
184+
content: {
185+
"application/json": {
186+
schema: z.array(getEventSchema),
187+
description: "Event data matching specified filter.",
188+
},
189+
},
190+
},
191+
},
182192
}),
183193
},
184194
async (request, reply) => {
@@ -315,6 +325,17 @@ const eventsPlugin: FastifyPluginAsyncZodOpenApi = async (
315325
example: "6667e095-8b04-4877-b361-f636f459ba42",
316326
}),
317327
}),
328+
response: {
329+
201: {
330+
description: "Event modified.",
331+
content: {
332+
"application/json": {
333+
schema: z.null(),
334+
},
335+
},
336+
},
337+
404: notFoundError,
338+
},
318339
summary: "Modify a calendar event.",
319340
}),
320341
) satisfies FastifyZodOpenApiSchema,
@@ -472,6 +493,17 @@ const eventsPlugin: FastifyPluginAsyncZodOpenApi = async (
472493
[AppRoles.EVENTS_MANAGER],
473494
withTags(["Events"], {
474495
body: postRequestSchema,
496+
response: {
497+
201: {
498+
description:
499+
"Event created. The 'Location' header specifies the URL of the created event.",
500+
content: {
501+
"application/json": {
502+
schema: z.null(),
503+
},
504+
},
505+
},
506+
},
475507
summary: "Create a calendar event.",
476508
}),
477509
) satisfies FastifyZodOpenApiSchema,
@@ -583,12 +615,17 @@ const eventsPlugin: FastifyPluginAsyncZodOpenApi = async (
583615
example: "6667e095-8b04-4877-b361-f636f459ba42",
584616
}),
585617
}),
586-
// response: {
587-
// 201: z.object({
588-
// id: z.string(),
589-
// resource: z.string(),
590-
// }),
591-
// },
618+
response: {
619+
204: {
620+
description: "Event deleted.",
621+
content: {
622+
"application/json": {
623+
schema: z.null(),
624+
},
625+
},
626+
},
627+
404: notFoundError,
628+
},
592629
summary: "Delete a calendar event.",
593630
}),
594631
) satisfies FastifyZodOpenApiSchema,
@@ -689,8 +726,18 @@ const eventsPlugin: FastifyPluginAsyncZodOpenApi = async (
689726
ts,
690727
includeMetadata: zodIncludeMetadata,
691728
}),
729+
response: {
730+
200: {
731+
description: "Event data.",
732+
content: {
733+
"application/json": {
734+
schema: getEventSchema,
735+
},
736+
},
737+
},
738+
404: notFoundError,
739+
},
692740
summary: "Retrieve a calendar event.",
693-
// response: { 200: getEventSchema },
694741
}),
695742
},
696743
async (request, reply) => {

src/api/routes/organizations.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AllOrganizationList } from "@acm-uiuc/js-shared";
33
import fastifyCaching from "@fastify/caching";
44
import rateLimiter from "api/plugins/rateLimiter.js";
55
import { withTags } from "api/components/index.js";
6+
import { z } from "zod/v4";
67

78
const organizationsPlugin: FastifyPluginAsync = async (fastify, _options) => {
89
fastify.register(fastifyCaching, {
@@ -20,6 +21,18 @@ const organizationsPlugin: FastifyPluginAsync = async (fastify, _options) => {
2021
{
2122
schema: withTags(["Generic"], {
2223
summary: "Get a list of ACM @ UIUC sub-organizations.",
24+
response: {
25+
200: {
26+
description: "List of ACM @ UIUC sub-organizations.",
27+
content: {
28+
"application/json": {
29+
schema: z
30+
.enum(AllOrganizationList)
31+
.default(JSON.stringify(AllOrganizationList)),
32+
},
33+
},
34+
},
35+
},
2336
}),
2437
},
2538
async (_request, reply) => {

0 commit comments

Comments
 (0)