Skip to content

Commit c946e67

Browse files
Merge pull request #1 from foyzulkarim/main
update from main
2 parents d59c4e5 + e54e698 commit c946e67

33 files changed

+809
-138
lines changed

.gitignore

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,6 @@ web_modules/
7272
# Yarn Integrity file
7373
.yarn-integrity
7474

75-
# dotenv environment variable files
76-
.env
77-
.env.development.local
78-
.env.test.local
79-
.env.production.local
80-
.env.local
81-
8275
# parcel-bundler cache (https://parceljs.org/)
8376
.cache
8477
.parcel-cache
@@ -128,3 +121,11 @@ dist
128121
.yarn/build-state.yml
129122
.yarn/install-state.gz
130123
.pnp.*
124+
125+
# ignore .env and config.{}.json files
126+
.env.development
127+
.env.production
128+
.env.test
129+
config.development.json
130+
config.production.json
131+
config.test.json

.vscode/snippets.code-snippets

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
{
2+
"Domain index file": {
3+
"prefix": "nbp-d-index",
4+
"body": [
5+
"const { routes } = require('./api');",
6+
"",
7+
"const defineRoutes = (expressRouter) => {",
8+
" expressRouter.use('/${1:route}', routes());",
9+
"};",
10+
"",
11+
"module.exports = defineRoutes;"
12+
],
13+
"description": "Nodejs boilerplate domain's index file"
14+
},
15+
"Domain API CRUD Routes": {
16+
"prefix": "nbp-d-api",
17+
"body": [
18+
"const express = require('express');",
19+
"const logger = require('../../libraries/log/logger');",
20+
"const { AppError } = require('../../libraries/error-handling/AppError');",
21+
"",
22+
"const {",
23+
" create,",
24+
" search,",
25+
" getById,",
26+
" updateById,",
27+
" deleteById,",
28+
"} = require('./service');",
29+
"",
30+
"const { createSchema, updateSchema, idSchema } = require('./request');",
31+
"const { validateRequest } = require('../../middlewares/request-validate');",
32+
"const { logRequest } = require('../../middlewares/log');",
33+
"",
34+
"const model = '${1:Product}';",
35+
"",
36+
"// CRUD for entity",
37+
"const routes = () => {",
38+
" const router = express.Router();",
39+
" logger.info(`Setting up routes for ${model}`);",
40+
"",
41+
" router.get('/', logRequest({}), async (req, res, next) => {",
42+
" try {",
43+
" // TODO: Add pagination and filtering",
44+
" const items = await search(req.query);",
45+
" res.json(items);",
46+
" } catch (error) {",
47+
" next(error);",
48+
" }",
49+
" });",
50+
"",
51+
" router.post(",
52+
" '/',",
53+
" logRequest({}),",
54+
" validateRequest({ schema: createSchema }),",
55+
" async (req, res, next) => {",
56+
" try {",
57+
" const item = await create(req.body);",
58+
" res.status(201).json(item);",
59+
" } catch (error) {",
60+
" next(error);",
61+
" }",
62+
" }",
63+
" );",
64+
"",
65+
" router.get(",
66+
" '/:id',",
67+
" logRequest({}),",
68+
" validateRequest({ schema: idSchema, isParam: true }),",
69+
" async (req, res, next) => {",
70+
" try {",
71+
" const item = await getById(req.params.id);",
72+
" if (!item) {",
73+
" throw new AppError(`${model} not found`, `${model} not found`, 404);",
74+
" }",
75+
" res.status(200).json(item);",
76+
" } catch (error) {",
77+
" next(error);",
78+
" }",
79+
" }",
80+
" );",
81+
"",
82+
" router.put(",
83+
" '/:id',",
84+
" logRequest({}),",
85+
" validateRequest({ schema: idSchema, isParam: true }),",
86+
" validateRequest({ schema: updateSchema }),",
87+
" async (req, res, next) => {",
88+
" try {",
89+
" const item = await updateById(req.params.id, req.body);",
90+
" if (!item) {",
91+
" throw new AppError(`${model} not found`, `${model} not found`, 404);",
92+
" }",
93+
" res.status(200).json(item);",
94+
" } catch (error) {",
95+
" next(error);",
96+
" }",
97+
" }",
98+
" );",
99+
"",
100+
" router.delete(",
101+
" '/:id',",
102+
" logRequest({}),",
103+
" validateRequest({ schema: idSchema, isParam: true }),",
104+
" async (req, res, next) => {",
105+
" try {",
106+
" await deleteById(req.params.id);",
107+
" res.status(204).json({ message: `${model} is deleted` });",
108+
" } catch (error) {",
109+
" next(error);",
110+
" }",
111+
" }",
112+
" );",
113+
"",
114+
" return router;",
115+
"};",
116+
"",
117+
"module.exports = { routes };"
118+
],
119+
"description": "CRUD routes for a model"
120+
},
121+
"Domain CRUD Service": {
122+
"prefix": "nbp-d-service",
123+
"body": [
124+
"const logger = require('../../libraries/log/logger');",
125+
"",
126+
"const Model = require('./schema');",
127+
"const { AppError } = require('../../libraries/error-handling/AppError');",
128+
"",
129+
"const model = '${1:product}';",
130+
"",
131+
"const create = async (data) => {",
132+
" try {",
133+
" const item = new Model(data);",
134+
" const saved = await item.save();",
135+
" logger.info(`create(): ${model} created`, {",
136+
" id: saved._id,",
137+
" });",
138+
" return saved;",
139+
" } catch (error) {",
140+
" logger.error(`create(): Failed to create ${model}`, error);",
141+
" throw new AppError(`Failed to create ${model}`, error.message);",
142+
" }",
143+
"};",
144+
"",
145+
"const search = async (query) => {",
146+
" try {",
147+
" const { keyword } = query ?? {};",
148+
" const filter = {};",
149+
" if (keyword) {",
150+
" filter.$or = [",
151+
" { name: { $regex: keyword, $options: 'i' } },",
152+
" { description: { $regex: keyword, $options: 'i' } },",
153+
" ];",
154+
" }",
155+
" const items = await Model.find(filter);",
156+
" logger.info('search(): filter and count', {",
157+
" filter,",
158+
" count: items.length,",
159+
" });",
160+
" return items;",
161+
" } catch (error) {",
162+
" logger.error(`search(): Failed to search ${model}`, error);",
163+
" throw new AppError(`Failed to search ${model}`, error.message, 400);",
164+
" }",
165+
"};",
166+
"",
167+
"const getById = async (id) => {",
168+
" try {",
169+
" const item = await Model.findById(id);",
170+
" logger.info(`getById(): ${model} fetched`, { id });",
171+
" return item;",
172+
" } catch (error) {",
173+
" logger.error(`getById(): Failed to get ${model}`, error);",
174+
" throw new AppError(`Failed to get ${model}`, error.message);",
175+
" }",
176+
"};",
177+
"",
178+
"const updateById = async (id, data) => {",
179+
" try {",
180+
" const item = await Model.findByIdAndUpdate(id, data, { new: true });",
181+
" logger.info(`updateById(): ${model} updated`, { id });",
182+
" return item;",
183+
" } catch (error) {",
184+
" logger.error(`updateById(): Failed to update ${model}`, error);",
185+
" throw new AppError(`Failed to update ${model}`, error.message);",
186+
" }",
187+
"};",
188+
"",
189+
"const deleteById = async (id) => {",
190+
" try {",
191+
" await Model.findByIdAndDelete(id);",
192+
" logger.info(`deleteById(): ${model} deleted`, { id });",
193+
" return true;",
194+
" } catch (error) {",
195+
" logger.error(`deleteById(): Failed to delete ${model}`, error);",
196+
" throw new AppError(`Failed to delete ${model}`, error.message);",
197+
" }",
198+
"};",
199+
"",
200+
"module.exports = {",
201+
" create,",
202+
" search,",
203+
" getById,",
204+
" updateById,",
205+
" deleteById,",
206+
"};"
207+
],
208+
"description": "CRUD service for a model"
209+
},
210+
"Mongoose Schema": {
211+
"prefix": "nbp-mongoose-schema",
212+
"body": [
213+
"const mongoose = require('mongoose');",
214+
"const { baseSchema } = require('../../libraries/db/base-schema');",
215+
"",
216+
"const schema = new mongoose.Schema({",
217+
" name: { type: String, required: true },",
218+
" // other properties",
219+
"});",
220+
"schema.add(baseSchema);",
221+
"",
222+
"module.exports = mongoose.model('${1:Model}', schema);"
223+
],
224+
"description": "Mongoose schema"
225+
},
226+
"Joi Validation Schemas": {
227+
"prefix": "nbp-joi-schemas",
228+
"body": [
229+
"const Joi = require('joi');",
230+
"const mongoose = require('mongoose');",
231+
"",
232+
"const createSchema = Joi.object().keys({",
233+
" name: Joi.string().required(),",
234+
" // other properties",
235+
"});",
236+
"",
237+
"const updateSchema = Joi.object().keys({",
238+
" name: Joi.string(),",
239+
" // other properties",
240+
"});",
241+
"",
242+
"const idSchema = Joi.object().keys({",
243+
" id: Joi.string()",
244+
" .custom((value, helpers) => {",
245+
" if (!mongoose.Types.ObjectId.isValid(value)) {",
246+
" return helpers.error('any.invalid');",
247+
" }",
248+
" return value;",
249+
" }, 'ObjectId validation')",
250+
" .required(),",
251+
"});",
252+
"",
253+
"module.exports = { createSchema, updateSchema, idSchema };"
254+
],
255+
"description": "Joi validation schemas"
256+
}
257+
}

package-lock.json

Lines changed: 39 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"scripts": {
1111
"test": "jest",
1212
"test:watch": "jest --watch --verbose",
13-
"start": "nodemon src/start.js"
13+
"start": "nodemon src/start.js",
14+
"create-domain": "zx scripts/dev/domain-generator.js"
1415
},
1516
"keywords": [],
1617
"author": "",
@@ -35,6 +36,7 @@
3536
"devDependencies": {
3637
"jest": "^29.7.0",
3738
"mongodb-memory-server": "^9.1.8",
38-
"supertest": "^6.3.4"
39+
"supertest": "^6.3.4",
40+
"zx": "^8.0.1"
3941
}
4042
}

0 commit comments

Comments
 (0)