Skip to content

Commit

Permalink
feat: implement basic project structure (#22)
Browse files Browse the repository at this point in the history
* feat: implement basic project structure

* Update src/middleware/globalErrorHandler/middleware.ts

Co-authored-by: Pat Heard <patrick.heard@cds-snc.ca>

* feat: add form submission router unit tests

---------

Co-authored-by: Pat Heard <patrick.heard@cds-snc.ca>
  • Loading branch information
craigzour and patheard authored Aug 9, 2024
1 parent 26ebf47 commit ac90c73
Show file tree
Hide file tree
Showing 24 changed files with 242 additions and 59 deletions.
11 changes: 10 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
const config = tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
Expand All @@ -12,6 +12,15 @@ export default tseslint.config(
{
rules: {
"no-undef": "off",
"@typescript-eslint/no-unused-vars": [
"warn",
{
args: "all",
argsIgnorePattern: "^_",
},
],
},
}
);

export default config;
8 changes: 0 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,6 @@
"version": "1.0.0",
"description": "Machine-to-machine interface for downloading form submissions",
"repository": "git@github.com:cds-snc/forms-api.git",
"prettier": {
"trailingComma": "es5",
"tabWidth": 2,
"printWidth": 100,
"useTabs": false,
"semi": true,
"singleQuote": false
},
"scripts": {
"build": "tsc",
"start": "node build/server.js",
Expand Down
10 changes: 10 additions & 0 deletions prettier.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const config = {
trailingComma: "es5",
tabWidth: 2,
printWidth: 100,
useTabs: false,
semi: true,
singleQuote: false,
};

export default config;
7 changes: 0 additions & 7 deletions src/lib/getSubmission.ts

This file was deleted.

8 changes: 8 additions & 0 deletions src/lib/vault/getSubmission.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
async function main(formId: string, submissionId: string) {
return {
formId,
submissionId,
};
}

export default main;
7 changes: 7 additions & 0 deletions src/middleware/authentication/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NextFunction, Request, Response } from "express";

async function main(request: Request, response: Response, next: NextFunction) {
next();
}

export default main;
8 changes: 8 additions & 0 deletions src/middleware/globalErrorHandler/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Request, Response, NextFunction } from "express";

function main(error: Error, _request: Request, response: Response, _next: NextFunction) {
console.error(JSON.stringify(error, Object.getOwnPropertyNames(error)));
response.sendStatus(500);
}

export default main;
7 changes: 7 additions & 0 deletions src/middleware/rateLimiter/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { NextFunction, Request, Response } from "express";

async function main(request: Request, response: Response, next: NextFunction) {
next();
}

export default main;
7 changes: 7 additions & 0 deletions src/middleware/routeNotFound/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Request, Response } from "express";

function main(_request: Request, response: Response) {
response.sendStatus(404);
}

export default main;
19 changes: 14 additions & 5 deletions src/router.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { Router } from "express";
import { route as formsRoute } from "./routes/forms";
import { route as healthCheckRoute } from "./routes/healthCheck";
import formsRouter from "./routes/forms/router";
import statusRouter from "./routes/status/router";
import routeNotFoundMiddleware from "./middleware/routeNotFound/middleware";
import globalErrorHandlerMiddleware from "./middleware/globalErrorHandler/middleware";

export const router = Router();
const router = Router();

router.use("/status", healthCheckRoute);
router.use("/forms", formsRoute);
router
.use("/forms", formsRouter)
.use("/status", statusRouter)
// 404: Catches all unmatched routes
.use(routeNotFoundMiddleware)
// 500: Catches all unhandled errors from non async functions and errors passed through next() in async functions
.use(globalErrorHandlerMiddleware);

export default router;
10 changes: 0 additions & 10 deletions src/routes/forms.ts

This file was deleted.

13 changes: 13 additions & 0 deletions src/routes/forms/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Router } from "express";
import submissionRouter from "./submission/router";
import authenticationMiddleware from "../../middleware/authentication/middleware";
import rateLimiterMiddleware from "../../middleware/rateLimiter/middleware";

const router = Router();

router
.use(authenticationMiddleware)
.use(rateLimiterMiddleware)
.use("/:formId/submission", submissionRouter);

export default router;
13 changes: 13 additions & 0 deletions src/routes/forms/submission/downloaded/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Request, Response, Router } from "express";

const router = Router({
mergeParams: true,
});

router.get("/", async (request: Request, response: Response) => {
response.json({
formId: request.params.formId,
});
});

export default router;
13 changes: 13 additions & 0 deletions src/routes/forms/submission/new/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Request, Response, Router } from "express";

const router = Router({
mergeParams: true,
});

router.get("/", async (request: Request, response: Response) => {
response.json({
formId: request.params.formId,
});
});

export default router;
15 changes: 15 additions & 0 deletions src/routes/forms/submission/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Router } from "express";
import newRouter from "./new/router";
import downloadedRouter from "./downloaded/router";
import submissionIdRouter from "./submissionId/router";

const router = Router({
mergeParams: true,
});

router
.use("/new", newRouter)
.use("/downloaded", downloadedRouter)
.use("/:submissionId", submissionIdRouter);

export default router;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Request, Response, Router } from "express";

const router = Router({
mergeParams: true,
});

router.put("/", async (request: Request, response: Response) => {
response.json({
formId: request.params.formId,
submissionId: request.params.submissionId,
confirmationCode: request.params.confirmationCode,
});
});

export default router;
10 changes: 10 additions & 0 deletions src/routes/forms/submission/submissionId/confirm/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Router } from "express";
import confirmationCodeRouter from "./confirmationCode/router";

const router = Router({
mergeParams: true,
});

router.use("/:confirmationCode", confirmationCodeRouter);

export default router;
18 changes: 18 additions & 0 deletions src/routes/forms/submission/submissionId/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Request, Response, Router } from "express";
import confirmRouter from "./confirm/router";
import getSubmission from "../../../../lib/vault/getSubmission";

const router = Router({
mergeParams: true,
});

router.get("/", async (request: Request, response: Response) => {
const formId = request.params.formId;
const submissionId = request.params.submissionId;
const submission = await getSubmission(formId, submissionId);
response.json(submission);
});

router.use("/confirm", confirmRouter);

export default router;
9 changes: 0 additions & 9 deletions src/routes/healthCheck.ts

This file was deleted.

11 changes: 11 additions & 0 deletions src/routes/status/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Response, Router } from "express";

const router = Router();

router.get("/", (_, response: Response) => {
response.json({
status: "running",
});
});

export default router;
6 changes: 2 additions & 4 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import express, { Express } from "express";
import { SERVER_PORT } from "./config";
import { router } from "./router";
import router from "./router";

const server: Express = express();

server.use("/", router);

server.listen(SERVER_PORT, () => {
console.log("-----------------------------------------");
console.log(`API server started on port ${SERVER_PORT}`);
console.log("-----------------------------------------");
console.log(`>>> API server listening on port ${SERVER_PORT} <<<`);
});
42 changes: 42 additions & 0 deletions test/routes/forms/submission/router.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { vi, describe, it, expect, beforeAll } from "vitest";
import request from "supertest";
import express from "express";
import router from "../../../../src/routes/forms/router";

vi.mock("../../../../src/middleware/authentication/middleware", () => ({
default: (_req, _res, next) => next(),
}));

vi.mock("../../../../src/middleware/rateLimiter/middleware", () => ({
default: (_req, _res, next) => next(),
}));

describe("routes/forms/submission", () => {
let app: express.Express;

beforeAll(() => {
app = express();
app.use("/", router);
});

it("GET /new", async () => {
const response = await request(app).get("/1234/submission/new");
expect(response.status).toBe(200);
expect(response.body).toEqual({ formId: "1234" });
});

it("GET /downloaded", async () => {
const response = await request(app).get("/1234/submission/downloaded");
expect(response.status).toBe(200);
expect(response.body).toEqual({ formId: "1234" });
});

it("GET /:submissionId", async () => {
const response = await request(app).get("/1234/submission/5678");
expect(response.status).toBe(200);
expect(response.body).toEqual({
formId: "1234",
submissionId: "5678",
});
});
});
15 changes: 0 additions & 15 deletions test/routes/healthCheck.test.ts

This file was deleted.

19 changes: 19 additions & 0 deletions test/routes/status/router.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { describe, it, expect, beforeAll } from "vitest";
import request from "supertest";
import express from "express";
import router from "../../../src/routes/status/router";

describe("routes/status", () => {
let app: express.Express;

beforeAll(() => {
app = express();
app.use("/", router);
});

it("GET /status", async () => {
const response = await request(app).get("/");
expect(response.statusCode).toBe(200);
expect(response.body).toEqual({ status: "running" });
});
});

0 comments on commit ac90c73

Please sign in to comment.