Authenticate
BAMIMI uses authentication with the fully-featured @knfs-tech/bamini-auth library. Additionally, BAMIMI's source includes authentication middleware that can be utilized on your router:
//src/routers/api/index.js
"use strict";
const router = require("express").
const authenticate = require("@iApp/http/middleware/apiAuthentication.mid")
router.get(
"/demo",
authenticate,
require("@iApp/http/controllers/api/demo").index
);
Security
BAMIMI has installed many security libraries and is pre-installed in the kernel.
For example @knfs-tech/csrf library, you can use it by adding to your router:
//src/routers/web/index.js
"use strict";
const router = require("express").
const { protect: csrfProtect } = require("@knfs-tech/csrf")
// Router to get form
router.get(
"/get-form",
require("@iApp/http/controllers/web/demo").getForm
);
// Router to request form
router.post(
"/save-form",
csrfProtect,
require("@iApp/http/controllers/web/demo").saveForm
);
BAMIMI also provides you with an email notification generator that can be integrated with jobs
npx @knfs-tech/bamimi-cli@latest email:generate demoEmail -tn demoEmail -job demoEmail
After running command line, the system immediately creates the following files:
//src/app/emails/demoEmail.email.js
"use strict";
const { renderTemplate } = require("@iUtils/mail");
const { QueueManager } = require("@knfs-tech/bamimi-schedule")
module.exports = (data) => {
const html = renderTemplate("demoEmail.ejs");
QueueManager
.singleton()
.getQueue("demoEmail")
.add("demoEmail", {
to: data.email,
subject: "Welcome to BAMIMI land",
html: html});
};
//src/app/jobs/demoEmail.job.js
"use strict";
const { sendMail } = require("@iUtils/mail");
module.exports = {
name: "demoEmail",
queue: "demoEmail",
handle: async function (job) {
await sendMail(job.data);
}
};
//src/configs/job.js
"use strict";
module.exports = [
{
name: "demoEmail",
func: require("@iApp/jobs/demoEmail.job"),
onMain: false //To set true if you want to run it concurrently on main processing
},
];
That's just a basic example of creating an email. You can see detailed usage with many cases at the the documentation
Job Queue
BAMIMI also integrated queue jobs because we know the use case is very popularnpx @knfs-tech/bamimi-cli@latest job:generate demoJob
After running command line, the system immediately creates the following files:
//src/app/jobs/demoJob.job.js
"use strict";
module.exports = {
name: "demoJob",
queue: "demoJob",
handle: async function (job) {}
};
//src/configs/job.js
"use strict";
module.exports = [
{
name: "demoJob",
func: require("@iApp/jobs/demoJob.job"),
onMain: false //To set true if you want to run it concurrently on main processing
},
];
There are many more job properties and how to use them in practice, see here job queue documentation
Task Scheduling
Effortlessly schedule recurring jobs and commands with a clear, expressive syntax—no more dealing with complex configuration files!
npx @knfs-tech/bamimi-cli@latest job:generate cronJob
? Is it cron job (Y/n):
After running command line, the system immediately creates the following files and you add more information for schedule:
//src/app/jobs/cronJob.job.js
"use strict";
module.exports = {
name: "cronJob",
queue: "cronJob",
schedules: [
{
name: "first-day-every-month",
time: {
pattern: "0 0 1 * *"
}, // cron schedule
prepare: { data: { email: "test@example.com" } },
},
],
handle: async function (job) {}
};
//src/configs/job.js
"use strict";
module.exports = [
{
name: "cronJob",
func: require("@iApp/jobs/cronJob.job"),
onMain: false //To set true if you want to run it concurrently on main processing
},
];
finally you need to run it
$ npm link .
$ bamimi-enjoy-<projectName>-dev job cronJob
Socket
BAMIMI integrated socket.io for handling real-time issue and event broadcasting issue with @knfs-tech/bamimi-socket.io
For example, in the case of a processing message when processing an uploaded excel file:
//src/routers/socket/index.js
"use strict";
const socket = require("@knfs-tech/bamimi-socket.io")
const AuthMiddleware = require("@iApp/http/middleware/socketAuth.mid")
const ImportChannel = require("@iApp/channels/import.channel")
socket.on("/import", AuthMiddleware, ImportChannel.import)
//src/app/channels/import.channel.js
"use strict";
const { getStorage } = require("@iKernel/cache")
const cache = getStorage().new
module.exports = {
import: async function (io, socket) {
const id = socket.handshake.currentUser.id;
const room = `import-excel:${id}`
await socket.join(room);
await cache.subscribe(`import-excel-process-${id}`, async (err, count) => {
if (err) {
console.error("Failed to subscribe to channels: ", err.message);
} else {
console.log(`Subscribed successfully to ${count} channels.`);
}
})
await cache.on("message", async (channel, message) => {
const msgData = await JSON.parse(String(message))
const event = "notify:"
console.info("event: " + event)
console.info("message: " + message)
io.of("/import").to(room).emit("get-log", msgData);
});
}
}
//src/app/jobs/import.job.js
"use strict";
const { getStorage } = require("@iKernel/cache")
const cache = getStorage().singleton
module.exports = {
name: "importJob",
queue: "importQueue",
handle: async function (job) {
console.group("-------------- START IMPORT EXCEL --------------")
console.time("Process Time");
const currentUser = job.data.currentUser;
for (let i = 0; i <= 100; i++) {
cache.publish(`import-excel-process-${id}`, JSON.stringify({
percentage: i,
}), (err, count) => {
if (err) {
console.error("Failed to publish: ", err.message);
} else {
console.log(`Message sent to ${count} subscriber(s).`);
}
})
}
console.info("--------------- END IMPORT EXCEL ---------------")
console.timeEnd("Process Time");
console.groupEnd();
}
}
Interface
BAMIMI fully develops interface three types API, Web UI, CLI.
{
meta: {
"content": "OK", // content message
"code": 200 // status of response
},
data: {
userData: {
id: 1,
username: "demo12345",
email: "demao12345@gmail.com"
}
}
}
to get the response as above the programmer only needs create interface:
npx @knfs-tech/bamimi-cli@latest itf:generate user
then we have generated file, you need to custom it
//@iApp/interfaces/apis/user.js
"use strict";
module.exports = (user) => {
return {
id: user.id,
username: user.username ?? null,
email: user.email ?? null
}
}
and declare it in:
//@iApp/interfaces/apis/index.js
/**
* Set interface you want to use
*/
module.exports = {
user: {
key: "userData", //representative field displayed at response
dto: require("./user") //format data
}
}
finally, we apply it in function of controller and router of api:
//@iApp/controllers/api/demo.controller.js
"use strict";
module.exports = {
getUser: async function (req, res, next) {
try {
const user = {
id: 1,
username: "demo12345",
email: "demao12345@gmail.com"
}
return res.status(200).sendUser(user) // or use default return res.status(200).sendData({userData: user})
} catch (error) {
next(error)
}
}
}
//@iRoutes/api/index.js
"use strict";
const router = require("express").Router();
router.get("/get-user", require("@iApp/http/controllers/api/demo.controller").getUser);
module.exports = router;
//@iApp/controllers/web/demo.controller.js
"use strict";
module.exports = {
index: async function (req, res, next) {
try {
return await res.view({
view: "pages/home", data: {
version: "1.0.0"
}
});
} catch (error) {
next(error)
}
}
};
//@iRoutes/cli/index.js
#!/usr/bin/env node
const { Command } = require("commander");
const program = new Command();
const jobCommand = require("@iKernel/job");
program
.addCommand(jobCommand)
program.parse(process.argv);
$ npm link .
$ bamimi-enjoy-<projectName>-dev // for dev
$ bamimi-enjoy-<projectName> // for build version
Testing
BAMIMI integrated Jest library for testing
//src/app/services/sum.js
"use strict";
function sum(a, b) {
return a + b;
}
module.exports = sum;
//test/units/services/sum.spec.js
"use strict";
const sum = require('@iApp/services/sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Docker
Deploying the project to different environments is very important, so we have created a docket file with three stages builder and development for future use and you can register it during project initialization
$ npx @knfs-tech/bamimi-cli@latest create demo-project
? Would you like to include a Dockerfile? (Y/n)
If you choose Yes (y/Y), the generated source code will include a DockerFile file with three stages
Or you can create by CLI:
npx @knfs-tech/bamimi-cli@latest docker:generate
# Stage 1: Builder
FROM node:20 AS builder
# Install necessary build tools
RUN apt-get update && apt-get install -y \
build-essential \
python3 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app
COPY --chown=node:node package.json yarn.lock ./
# Install dependencies for building
RUN yarn install --production=false
COPY --chown=node:node . .
RUN yarn build
# Stage 2: Development
FROM node:20-slim as development
# Copy only the dist directory from the builder stage
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
COPY --from=builder /usr/src/app/package.json /usr/src/app/package.json
COPY --from=builder /usr/src/app/node_modules /usr/src/app/node_modules
COPY --from=builder /usr/src/app/.env /usr/src/app/.env
ENV NODE_ENV=development
WORKDIR /usr/src/app
RUN yarn install --production=false --ignore-scripts
EXPOSE 3000
CMD ["yarn", "start"]
# Stage 3: Production
FROM node:20-slim as production
# Copy only the dist directory from the builder stage
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
COPY --from=builder /usr/src/app/package.json /usr/src/app/package.json
COPY --from=builder /usr/src/app/.env /usr/src/app/.env
ENV NODE_ENV=production
WORKDIR /usr/src/app
RUN yarn install --production
EXPOSE 3000
CMD ["yarn", "start"]
We've only begun to explore the possibilities. With BAMIMI, you have everything you need to build a complete web application—email verification, linting, and even custom console commands. Dive into the documentation to continue your journey!