Skip to content

Commit

Permalink
Fix default for unspecified specification
Browse files Browse the repository at this point in the history
Changes parameters, query, and body to have empty/unknown default types.
This means using them when not defined in spec will result in an error
instead of being typed as unknown.

As such, this also fixes two missed cases in users and notifications
that were caught by this change.
  • Loading branch information
Timothy-Gonzalez committed Oct 16, 2024
1 parent 84a09fb commit 31851e9
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 6 deletions.
13 changes: 8 additions & 5 deletions src/middleware/specification.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RequestHandler } from "express";
import { AnyZodObject, z, ZodType } from "zod";
import { AnyZodObject, z, ZodObject, ZodType, ZodUnknown } from "zod";
import StatusCode from "status-code-enum";
import { Response, Request, NextFunction } from "express";
import { registerPathSpecification } from "../common/openapi";
Expand Down Expand Up @@ -36,7 +36,7 @@ export interface ResponsesObject {
[statusCode: string]: ResponseObject;
}

export interface Specification<Params = AnyZodObject, Query = AnyZodObject, Responses = ResponsesObject, Body = ZodType> {
export interface Specification<Params = ZodUnknown, Query = ZodUnknown, Responses = ResponsesObject, Body = ZodUnknown> {
path: string;
method: Method;
tag: Tag;
Expand All @@ -53,11 +53,14 @@ export interface Specification<Params = AnyZodObject, Query = AnyZodObject, Resp
type InferResponseBody<T> = T extends ResponseObject ? z.infer<T["schema"]> : never;
type ResponseBody<T extends ResponsesObject> = InferResponseBody<T[keyof T]>;

// Utility type for a zod object which is really just empty
type ZodEmptyObject = ZodObject<NonNullable<unknown>>;

export default function specification<
Params extends AnyZodObject,
Query extends AnyZodObject,
Responses extends ResponsesObject,
Body extends ZodType,
Params extends AnyZodObject = ZodEmptyObject,
Query extends AnyZodObject = ZodEmptyObject,
Body extends ZodType = ZodUnknown,
>(spec: Specification<Params, Query, Responses, Body>): RequestHandler<z.infer<Params>, ResponseBody<Responses>, z.infer<Body>> {
registerPathSpecification(spec);

Expand Down
8 changes: 7 additions & 1 deletion src/services/notification/notification-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import Models from "../../database/models";
import { StaffShift } from "../staff/staff-schemas";
import { Role } from "../auth/auth-schemas";
import { getAuthenticatedUser } from "../../common/auth";
import { NotificationSendRequestSchema, NotificationSendSchema, NotificationsSchema } from "./notification-schemas";
import {
NotificationSendRequestSchema,
NotificationSendSchema,
NotificationsSchema,
RegisterDeviceTokenSchema,
} from "./notification-schemas";
import { sendNotification } from "./notification-service";
import specification, { Tag } from "../../middleware/specification";
import { SuccessResponseSchema } from "../../common/schemas";
Expand Down Expand Up @@ -41,6 +46,7 @@ notificationsRouter.post(
tag: Tag.NOTIFICATION,
role: Role.USER,
summary: "Registers a device token to be associate with the currently authenticated user",
body: RegisterDeviceTokenSchema,
responses: {
[StatusCode.SuccessOK]: {
description: "Successfully registered",
Expand Down
3 changes: 3 additions & 0 deletions src/services/user/user-router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ userRouter.delete(
tag: Tag.USER,
role: Role.USER,
summary: "Unfollows the specified event",
parameters: z.object({
id: UserIdSchema,
}),
responses: {
[StatusCode.SuccessOK]: {
description: "Events followed after successfully unfollowing",
Expand Down

0 comments on commit 31851e9

Please sign in to comment.