Skip to content

Commit effa102

Browse files
Initial MVP of Question Service
1 parent b74ba5e commit effa102

File tree

11 files changed

+1328
-0
lines changed

11 files changed

+1328
-0
lines changed

questions/.gitignore

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env*.local
29+
30+
# vercel
31+
.vercel
32+
33+
# typescript
34+
*.tsbuildinfo
35+
next-env.d.ts

questions/nodemon.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"watch": ["src"],
3+
"ext": ".ts,.js",
4+
"exec": "ts-node ./src/index.ts"
5+
}

questions/package.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "questions",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"dev": "nodemon"
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"body-parser": "^1.20.2",
13+
"compression": "^1.7.4",
14+
"cors": "^2.8.5",
15+
"express": "^4.18.2",
16+
"mongoose": "^7.5.1"
17+
},
18+
"devDependencies": {
19+
"@types/body-parser": "^1.19.2",
20+
"@types/compression": "^1.7.3",
21+
"@types/cors": "^2.8.14",
22+
"@types/express": "^4.17.17",
23+
"@types/mongoose": "^5.11.97",
24+
"dotenv": "^16.3.1",
25+
"nodemon": "^3.0.1",
26+
"ts-node": "^10.9.1",
27+
"typescript": "^5.2.2"
28+
}
29+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import express from "express";
2+
import { QuestionDao } from "../models/questions";
3+
import { ApiResponse, EMPTY_OBJECT, StatusMessageType } from "../types";
4+
5+
// GET /questions/:id
6+
export const getQuestion = async (
7+
req: express.Request,
8+
res: express.Response
9+
) => {
10+
try {
11+
const id = req.params.id;
12+
if (!id) {
13+
const response: ApiResponse = {
14+
payload: EMPTY_OBJECT,
15+
statusMessage: {
16+
type: StatusMessageType.ERROR,
17+
message: "No ID provided",
18+
},
19+
};
20+
21+
res.status(400).json(response);
22+
}
23+
24+
const question = await QuestionDao.getQuestionById(id);
25+
if (!question) {
26+
const response: ApiResponse = {
27+
payload: EMPTY_OBJECT,
28+
statusMessage: {
29+
type: StatusMessageType.ERROR,
30+
message: "No question found",
31+
},
32+
};
33+
34+
res.status(404).json(response);
35+
}
36+
37+
const response: ApiResponse = {
38+
payload: question,
39+
statusMessage: null,
40+
};
41+
res.status(200).json(response);
42+
} catch (error) {
43+
console.log(error);
44+
const response: ApiResponse = {
45+
payload: EMPTY_OBJECT,
46+
statusMessage: {
47+
type: StatusMessageType.ERROR,
48+
message: "Something went wrong",
49+
},
50+
};
51+
52+
res.status(500).json(response);
53+
}
54+
};
55+
56+
// POST /questions
57+
export const createQuestion = async (
58+
req: express.Request,
59+
res: express.Response
60+
) => {
61+
try {
62+
const { title, description } = req.body;
63+
if (!title || !description) {
64+
const response: ApiResponse = {
65+
payload: EMPTY_OBJECT,
66+
statusMessage: {
67+
type: StatusMessageType.ERROR,
68+
message: "Title or description must provided",
69+
},
70+
};
71+
72+
res.status(400).json(response);
73+
}
74+
75+
const question = await QuestionDao.createQuestion(title, description);
76+
const response: ApiResponse = {
77+
payload: question,
78+
statusMessage: null,
79+
};
80+
res.status(201).json(response);
81+
} catch (error) {
82+
console.log(error);
83+
const response: ApiResponse = {
84+
payload: EMPTY_OBJECT,
85+
statusMessage: {
86+
type: StatusMessageType.ERROR,
87+
message: "Something went wrong",
88+
},
89+
};
90+
91+
res.status(500).json(response);
92+
}
93+
};

questions/src/index.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import express from "express";
2+
import bodyParser from "body-parser";
3+
import compression from "compression";
4+
import cors, { CorsOptions } from "cors";
5+
import http from "http";
6+
import mongoose from "mongoose";
7+
import router from "./router";
8+
9+
const MONGO_URL = "mongodb://localhost:27017/questions";
10+
11+
mongoose.Promise = Promise;
12+
mongoose.connect(MONGO_URL);
13+
mongoose.connection.on("error", console.error);
14+
15+
const corsOptions: CorsOptions = {
16+
origin: "*",
17+
};
18+
19+
const app = express();
20+
21+
app.use(cors(corsOptions));
22+
app.use(compression());
23+
app.use(bodyParser.json());
24+
25+
const server = http.createServer(app);
26+
27+
server.listen(3000, () => {
28+
console.log("Server is listening on port 3000");
29+
});
30+
31+
app.use("/", router());

questions/src/models/questions.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import mongoose from "mongoose";
2+
3+
const QuestionSchema = new mongoose.Schema({
4+
title: { type: String, required: true },
5+
description: { type: String, required: true },
6+
});
7+
8+
const QuestionModel = mongoose.model("Question", QuestionSchema);
9+
10+
const getQuestionById = async (id: string) =>
11+
QuestionModel.findById(id).then((question) => question?.toObject());
12+
const createQuestion = async (title: string, description: string) => {
13+
const question = new QuestionModel({ title, description });
14+
return question.save().then((question) => question.toObject());
15+
};
16+
17+
export const QuestionDao = {
18+
getQuestionById,
19+
createQuestion,
20+
};

questions/src/router/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import express from "express";
2+
import questions from "./questions";
3+
4+
const router = express.Router();
5+
6+
export default (): express.Router => {
7+
questions(router);
8+
return router;
9+
};

questions/src/router/questions.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { createQuestion, getQuestion } from "../controllers/questions";
2+
import express from "express";
3+
4+
export default (router: express.Router) => {
5+
router.get("/questions/:id", getQuestion);
6+
router.post("/questions", createQuestion);
7+
};

questions/src/types/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const EMPTY_OBJECT = {};
2+
3+
export enum StatusMessageType {
4+
ERROR = "ERROR",
5+
SUCCESS = "SUCCESS",
6+
}
7+
8+
export interface StatusMessage {
9+
type: StatusMessageType;
10+
message: string;
11+
}
12+
13+
export interface ApiResponse {
14+
payload: Object;
15+
statusMessage: StatusMessage | null;
16+
}

questions/tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"module": "NodeNext",
4+
"moduleResolution": "node",
5+
"baseUrl": "src",
6+
"outDir": "dist",
7+
"sourceMap": true,
8+
"noImplicitAny": true
9+
},
10+
"include": ["src/**/*"]
11+
}

0 commit comments

Comments
 (0)