Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,12 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@asteasolutions/zod-to-openapi": "^7.3.4",
"@eslint/js": "^9.24.0",
"@jest/globals": "^29.7.0",
"@types/bcrypt": "^5.0.2",
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.21",
"@types/express": "4.17.21",
"@types/express-rate-limit": "^6.0.0",
"@types/jest": "^29.5.12",
"@types/jsonwebtoken": "^9.0.6",
Expand All @@ -70,14 +71,19 @@
"@types/passport-google-oauth20": "^2.0.14",
"@types/pg": "^8.15.2",
"@types/supertest": "^6.0.2",
"@types/swagger-jsdoc": "^6.0.4",
"@types/swagger-ui-express": "^4.1.8",
"@types/uuid": "^10.0.0",
"cross-env": "^7.0.3",
"eslint": "^9.24.0",
"globals": "^16.0.0",
"jest": "^29.7.0",
"nodemon": "^3.0.1",
"openapi-types": "^12.1.3",
"prettier": "3.2.5",
"supertest": "^7.0.0",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"ts-jest": "^29.1.4",
"typescript-eslint": "^8.29.1"
},
Expand Down
74 changes: 73 additions & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import express, { Request, Response } from "express";
import express, { Request, Response, RequestHandler } from "express";
import { StatusCodes } from "http-status-codes";
import { Config, EnvironmentEnum } from "./config";
import { isTest } from "./utilities";
Expand Down Expand Up @@ -32,10 +32,82 @@ import leaderboardRouter from "./services/leaderboard/leaderboard-router";

import cors from "cors";
import { JwtPayloadValidator } from "./services/auth/auth-models";
import swaggerJsdoc from "swagger-jsdoc";
import { registry } from "./middleware/openapi-registry";
import { OpenApiGeneratorV3 } from "@asteasolutions/zod-to-openapi";
import swaggerUi from "swagger-ui-express";
import { createServer } from "http";
import { WebSocketServer } from "ws";
import path from "path";

const app = express();

// generate openapi schemas from zod
const generator = new OpenApiGeneratorV3(registry.definitions);
const openApiComponents = generator.generateComponents();

// set up swagger-ui docs
const swaggerOptions: swaggerJsdoc.Options = {
definition: {
openapi: "3.0.0",
info: {
title: "R|P API",
version: "1.0.0",
description: "Documentation for the Reflections|Projections API",
},
// configures the "Authorize" button for JWTs
components: {
...openApiComponents.components,
securitySchemes: {
USER: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
STAFF: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
description: "Requires the 'staff' role in the JWT payload",
},
ADMIN: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
description: "Requires the 'admin' role in the JWT payload",
},
},
},
// sets default needed authorization for endpoints (in docs)
security: [
{
bearerAuth: [],
},
],
},
// Tells Swagger to look for JSDoc comments in all TypeScript files inside your services folder
apis: [path.join(__dirname, "./services/**/*-router.ts")],
};

// console.log("Swagger scanned APIs:", swaggerOptions.apis);

const swaggerSpec = swaggerJsdoc(swaggerOptions);

app.use(
"/docs",
swaggerUi.serve as unknown as RequestHandler,
swaggerUi.setup(swaggerSpec) as unknown as RequestHandler
);

// do we only want to serve docs in development (in that case wrap the whole thing to avoid generating schemas etc)
// if (Config.ENV !== EnvironmentEnum.PRODUCTION) {
// app.use("/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec));
// app.get("/docs.json", (req, res) => {
// res.setHeader("Content-Type", "application/json");
// res.send(swaggerSpec);
// });
// }

const server = createServer(app);
const wss = new WebSocketServer({ server });

Expand Down
38 changes: 38 additions & 0 deletions src/middleware/openapi-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
extendZodWithOpenApi,
OpenAPIRegistry,
} from "@asteasolutions/zod-to-openapi";
import z from "zod";
// add .openapi to zod objects
extendZodWithOpenApi(z);
// create an openapi registry to register schemas to
export const registry = new OpenAPIRegistry();

// add an error type to the registry
export const ErrorSchema = registry.register(
"Error",
z
.object({
error: z.string(),
})
.openapi("Error")
);

// const makeError = (code: string, example?: string) =>
// ErrorSchema.extend({
// error: z.literal(code),
// }).openapi({
// example: { error: example ?? code },
// });

// registry.register("DoesNotExistError", makeError("DoesNotExist"));
// registry.register("UserNotFoundError", makeError("UserNotFound"));
// registry.register("EventNotFoundError", makeError("EventNotFound"));
// registry.register(
// "TierAlreadyRedeemedError",
// makeError("Tier already redeemed")
// );
// registry.register(
// "UserTierTooLowError",
// makeError("User tier too low for redemption")
// );
Loading
Loading