বাংলা আর্টিকেল:{Organize your Crud Code} Learn MERN Stack By Create Real-Estate Project -Part_4

বাংলা আর্টিকেল:{Organize your Crud Code} Learn MERN Stack By Create Real-Estate Project -Part_4

(Organize your Crud Code) ->Create a Real-estate Management Full-Stack Project To Learn React, NodeJs, MongoDB, Prisma And More Web Tools.

তুমি কি খেয়াল করছ ? আমরা প্রজেক্ট করতে এসে, অলরেডি একটা ছোট্ট প্রজেক্ট কমপ্লিট করে ফেলেছি।! তুমি এটাকে বাচ্চা প্রজেক্ট বলতে পার। আবার ,এই বাচ্চাটাই বড় আকার দেয়া সম্ভব,crm ,cms এমন অনেক টাইপ প্রজেক্ট পর্যন্ত নিয়ে যাওয়া সম্ভব।

প্রায় সব গুলো ওয়েব এপ্লিকেশন দাঁড়ায় আছে crud এর উপর। সেই একই কাজ ,ডাটা দেখাও ,ডাটা বানাও ,ডাটা মুছেফেল ,ডাটা আপডেট কর, এই তো।

কিন্তু ,তোমার মনে প্রশ্ন আসতেই পারে ,ভাই crud তো সবাই পারে ,তাইলে সবাই ক্যান সিনিয়র ডেভেলপার হয় না ! কিংবা জব পায় না ?

আদতে ,কথা হচ্ছে কোড সবাই করতে পারে ।

ইভেন ,এখন তো জেনারেটিভ chatbot আছে chatgpt, সেও কোড করতে পারে। কিন্তু একজন সিনিয়র ডেভেলপার ,কোড করার সাথে ,পারফর্মেন্স অপটিমাইজেশন ,ব্যালেন্স the লোড ইন এপ্লিকেশন ,algo ,ds,কোড অর্গানাইজ আর সবথেকে ইম্পর্টেন্ট থিংকিং প্রসেস apply করে।

একজন সিনিয়র আর জুনিও ডেভেলপার এর মধ্যে পার্থক্য হচ্ছে ,সিনিয়র ডেভলোপার এর কোড থাকে অর্গানাইজ করা। তার সব কনসেপ্ট থাকে ক্লিয়ার । সে জানে কখন কি লাগবে ,কি করলে আমার এপ্লিকেশন বেটার পারফর্মেন্স provid করবে।

আজকাল তো কোলাবোরেশন এর যুগ ,তোমার কোড শুধু তুমি একা না আরো টীম মেম্বার থাকবে কম্পানিতে যারা তোমার সাথে কাজ করবে। তাই , অর্গানাইজ করে কোড করা দরকার যেন ,অন্য সবাই কোড দেখলে বুজতে পারে ,কি হচ্ছে এপ্লিকেশন এ ।

এপ্লিকেশন ডেভলপমেন্ট এ , আজকাল আমরা একটা টার্মস খুব শুনি ,ফ্রেমওয়ার্ক ।

এই ফ্রেমওয়ার্ক ভালো ,এইটা শিখলে ডিমান্ড কেমন ,ওইটা তো হাইপ তুলে ফেলছে,আর আমরা দৌড়াই তার পিছনে । বিগিনার লেবেলে এই প্রব্লেম গুলো সব থেকে বেশি।

ফান্ডামেন্টাল শেখার সময় ভাবি ,আমরা যা শিখছি তা ঠিক আছে তো ? নাকি একটা ফ্রেমওয়ার্ক বা লাইব্রেরি শেখা উচিত ?

কিন্তু আমরা এমন করে ভাবি না , row কোড দিয়েই তো ফ্রেমওয়ার্ক তৈরী হয় , লাইব্রেরি তো জাস্ট আমাদের সময় কে সেভ করে । আমি যদি ফান্ডামেন্টাল না জানি ,তবে ফ্রেমওয়ার্ক বা লাইব্রেরি কি করে বুঝব ?

অন্যদিকে , সিনিয়রিটি আসে সময়ের সাথে , এই যেমন ধর ,একটা ছোট্ট crud ,এটাকে তুমি তোমার ভাবনা দিয়ে ,চিন্তা দিয়ে নেক্সট লেবেল এ কিভাবে নিয়ে যাবে, সেটাই তোমার ভারসাইলিটি।

হ্যা, এটা ঠিক শুধু crud জানলে হবে না ,এর সাথে অথেন্টিকেশন আছে , লজিক আছে , এমন অনেক ছোট ছোট জিনিস তোমায় জানতে হবে । কিন্তু শুরুটা এখানেই। কিছু শেষ করার পূর্ব সূত্র হচ্ছে সেটাকে শুরু করা ।

এই যে লাস্ট দুই চ্যাপ্টার ধরে ,তুমি শুনেই যাচ্ছ one to one ,one to many এসব হচ্ছে কনসেপ্ট । তুমি যখন জেনে যাবে কোনটা করলে কি হয়। তখন নিজেই ডিসিশন নিতে পারবে, আমার এপ্লিকেশন এ কোন রিলেশনাল approch ফলো করা দরকার। কোন ভাবে আগলে এপ্লিকেশন, আমি যা তাই ফিডব্যাক দিবে। জানতে হবে সময় দিয়ে ,ভাবতে হবে এপ্লিকেশন নিয়ে এবং ব্যাসিক থাকতে হবে ক্লিয়ার।

তুমি যদি জাভাস্ক্রিপ্ট জান ,অদূর ভবিষ্যতে ,এই ইকোসিস্টেম এ যে ফ্রেমওয়ার্ক আসুকনা কেন ,তোমার ফান্ডামেন্টাল নলেজ ব্যবহার করে চটজলদি তুমি তা আয়ত্ত করে ফেলতে পারবে।

Note: কনসেপ্ট বুঝ , কোড অর্গানাইজ কর ,এপ্লিকেশন নিয়ে ভাবো ,ফান্ডামেন্টাল আর বেসিক রাখো স্মুথ। এসব তোমায় তোমার লক্ষে পৌঁছে দিবে। প্রজেক্ট করো বেশি বেশি ,প্রজেক্ট এ আটকে গেলে বা ব্যাসিক না বুজলে ব্যাক এ চলে যায়। শিখে ফেলো কি বুজতেছো না। প্রশ্ন কর ,comunnity তে একটিভ থাক ।

যাইহোক ,

Hey Script_Slingers,

স্বাগতম তোমায় নতুন আরো একটা চ্যাপ্টার এ। দেখতে দেখতে বাংলা আর্টিকেল:Learn MERN Stack By Create Real-Estate Project -Part_4 এ চলে আসলাম।

প্রজেক্ট এর এই অবস্থায় আমাদের টার্গেট হচ্ছে prisma ও crud এর সাথে নিজেদের স্ট্রংলি বাইন্ড করা। গত পর্বে আমরা দেখেছি one-to-one রেলশনশিপ । করেফেলেছি ,একটা ছোট্ট crud । যা এপ্লিকেশন এর ব্যাসিক।

তুমি, আগের পর্বের দেয়া ইনফরমাল কনভার্সেশন থেকে হয়তো অলরেডি ক্লিয়ার হয়ে গেছো one to one রিলেশন এর মূল কনসেপ্ট কি। তবে ,যদি না হয় dont worry ফিরেযাও পিছনে দেখে আসো আর একবার। আমরা সামনে এসব, নিয়ে বিস্তারিত আলোচনা করতেই থাকব। আর সাথে আসবে আরো নতুন নতুন কনসেপ্ট ।

__আজকের এজেন্ডা _

গতকালকের crud এপ্লিকেশন এর কথা মনে আছে আশাকরছি। আমরা আমাদের সব কোড index.js ফাইল এর মধ্যে করেছিলাম। এটা যদিও ঠিক ভাবে কাজ করে তবে ,এতে,করে কোড অর্গানাইজ হয় না । অন্য কেও কোড দেখলে হয়ত বুঝে যাবে আমাদের অর্গানাইজ মেন্টালিটি নেই ,যা জুনিয়র ডেভেলপার approch ।

আর তা ছাড়া তুমি নিজেও যদি, এক সপ্তাহ পরে নিজের কোড দেখো আমি sure ,তুমি নিজেও বুজবে না । কনভিনিয়ান্ট ওয়ে তে প্রথম থেকে কোড করা ,পরবর্তীতে ডিবাগিং করার জন্য আমাদের হাজার হাজার সেকেন্ড সময় বাঁচাতে পারে ।

তাই ,আজ আমরা ছোট করে ,আমাদের কোড গুলোকে বিজনেস লজিক ও কাজ এর উপর ভিত্তি করে আলাদা করে ফেলবো। যেন বুজতে পারি ,How actually joint the dots together এবং বেটার আউটপুট পাই লং রানে ।

ক্রিকেট এ , oneday ,t20 থেকে টেস্ট ম্যাচ কে গুরুত্ব দেয়াহয় বেশি। কারণ এটা একজন প্লেয়ার কে অর্গানাইজ করে।

ঠিক তেমনি তুমি সময় দিয়ে নিজেকে গুছিয়ে নিতে পারলে , তোমার প্রোগরামিং, লাইফ এর oneday ,t20 সহজ হয়ে যাবে।

চল শুরু করি,

#Reflector_One-to-one_CRUD:

আমাদের এপ্লিকেশন এর আর্কিটেকচার হিসেবে আমরা ফলো করব "MVC" প্যাটার্ন।

মানে মডেল ,ভিউ ,কন্ট্রোলার। মডেল আমাদের সব ডাটা গুলোকে নিয়ে কাজ করবে যা prisma.schema ফাইল এর মধ্যে অলরেডি করেছি ,Controllers আমাদের সব বিজনেস লজিক যেমন ,রিকোয়েস্ট হ্যান্ডেল করা ,মডেলের সাথে ইন্টারঅ্যাকশন করা এসব হ্যান্ডেল করবে।

Routers সব URL paths বা api এন্ডপয়েন্ট গুলো নিয়ে কাজ করবে।

এবং View যা আমাদের ক্লায়েন্ট side মানে, react হ্যান্ডেল করবে। এভাবে অর্গানিজ কোড করলে আমাদের সুবিধা হচ্ছে প্রত্যেক কে আলাদা ভাবে ডেফিনেট করতে পারবো।

এখন তোমার কাজ হচ্ছে সার্ভার ফোল্ডার এর মধ্যে ৩ টা ফোল্ডার তৈরী করা। ফোল্ডার গুলোর নাম হবে ,controllers ,routes ,config ।

নিচের ইমেজ এ দেখো :

এবারে,

#prismaConfig.js :

config ফোল্ডার এ prismaConfig.js নামে একটা ফাইল create করো ,যা আমাদের prismaClient হ্যান্ডেল করবে।

//config/prismaClient.js
import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

export default prisma

আমরা, ঠিক আগের মতোই PrismaClient ইম্পোর্ট করে নিয়ে আসছি @prisma/client থেকে এবং prisma নামের ভ্যারিয়েবল এ ইনস্ট্যান্স create করছি।

then ES6 module ফিচার ব্যবহার করে এক্সপোর্ট করে দিয়েছি,যাতে করে অন্য যে কোন জায়গায় আমাদের prisma দরকার হলে জাস্ট ইম্পোর্ট করে use করতে পারি।

Note: আমি বিশ্বাস করি তুমি জাভাস্ক্রিপ্ট শেষ করেই এখানে আসছো। তাই ইম্পোর্ট ,এক্সপোর্ট কিভাবে কাজ করে তা যান।

#userController.js :

controllers ফোল্ডারের মধ্যে userController.js নামে একটা ফাইল তৈরী কর ,যা আমাদের user এর সব বিজনেস লজিক গুলোকে control করবে।

//controllers/userController.js
import prisma from "../config/prismaClient.js";

// Create a new user and profile

const createUser = async (req, res) => {
  try {
    const { email, profile } = req.body;

    // Use email to check for an existing user
    const existingUser = await prisma.user.findUnique({
      where: { email: email },
    });

    if (!existingUser) {
      const user = await prisma.user.create({
        data: {
          email,
          profile: {
            create: profile,
          },
        },
        include: {
          profile: true,
        },
      });
      res.json(user);
    } else {
      res.json({
        message: "User Already Existed!",
        user: existingUser,
      });
    }
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Failed to create user." });
  }
};

// Get all users
const getUserData = async (_req, res) => {
  try {
    const users = await prisma.user.findMany({
      include: {
        profile: true,
      },
    });
    if (users.length <= 0) {
      res.json({ message: "No Data Found" });
    }
    res.json(users);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Failed to retrieve users." });
  }
};

// Update a user's email
const updateUserData = async (req, res) => {
  try {
    const { userEmail } = req.params;
    const { email } = req.body;
    const updatedUser = await prisma.user.update({
      where: { email: userEmail },
      data: { email },
    });
    res.json(updatedUser);
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Failed to update user." });
  }
};

// Delete a user
const deleteUser = async (req, res) => {
  try {
    const { userEmail } = req.params;

    const findProfile = await prisma.profile.findFirst({
      where: { userEmail: userEmail },
    });
    if (findProfile)
      await prisma.profile.delete({ where: { userEmail: userEmail } });

    await prisma.user.delete({ where: { email: userEmail } });

    res.json({ message: "User deleted & Associate Profile Deleted." });
  } catch (error) {
    console.error(error);
    res.status(500).json({ error: "Failed to delete user." });
  }
};

export { createUser, getUserData, updateUserData, deleteUser };

আমাদের prismaClient এক্সপোর্ট করাই আছে । তাই , প্রথমেই আমরা prisma ফাইল ইম্পোর্ট করছি import prisma from "../config/prismaClient.js" এবং আমাদের প্রত্যেকটা crud অপারেশন এর জন্য একটা করে অসিনক্রোনাস ফাঙ্কশন ডিক্লার করছি ও ভ্যারিয়েবল এ স্টোর করছি।

যেমন ধর ,createUser ফর ইউসার create করতে , getUserData ফর ডাটা গেট করতে ,এমন আর কি।

এটা করার কারণ হচ্ছে, যাতে করে আমাদের ফাঙ্কশন গুলোকে এক্সপোর্ট করতে পারি ,others যেখানে লাগবে জাস্ট নাম ধরে ইম্পোর্ট করে use করা ফেলব।

basically আমাদের routing করার সময় এর দরকার হবে।

Note: If you create an asynchronous function and store it in a variable, it is commonly referred to as a "promisified function" or a "promisified asynchronous function."

Promisification is a process where you take a function that uses callbacks for handling asynchronous operations and convert it into a function that returns a Promise. This makes it easier to work with asynchronous code using modern async/await syntax and allows for better error handling and chaining of operations.

then লাস্ট এ export { createUser,getUserData,updateUserData,deleteUser } প্রত্যেকটা ফাঙ্কশন কে এক্সপোর্ট করে দিয়েছি।

#userRoute.js :

routers ফোল্ডার এর মধ্যে userRoute.js নামে একটা ফাইল create করো ,যা আমাদের user এর সকল API এন্ডপয়েন্ট বা url কন্ট্রোল করবে।

//routes/userRoute.js
import express from "express";
import {
  createUser,
  getUserData,
  updateUserData,
  deleteUser,
} from "../controllers/userController.js";

const router = express.Router();

router.post("/users", createUser);
router.get("/users", getUserData);
router.put("/users/:userEmail", updateUserData);
router.delete("/users/:userEmail", deleteUser);

export { router as userRouter };

এপর্যায়ে ,express ইম্পোর্ট করেছি from express ও userController থেকে createUser,getUserData,updateUserData,deleteUser ফাঙ্কশন গুলোকে ইম্পোর্ট করে নিয়ে আসছি।

এক্সপ্রেস, আমাদের Router নামে একটা মেথড provide করে, যার মাধ্যমে আমরা HTTP রিকোয়েস্ট গুলোকে হ্যান্ডেল করতে পারি।

তুমি router বা যেকোন নামের একটা ভ্যারিয়েবল এ Router মেথড কে স্টোর করতে পার ,আমি const router = express.Router() দিয়েছি ।

Note: storing express.Router() in a router variable is a common practice to improve code organization, readability, and maintainability when defining routes for your Express application.

তুমি router ভ্যারিয়েবল থেকে সব গুলো HTTP মেথড পেয়ে যাবে যেমন, get,post,put,delete,patch এমন সব। এই মেথড গুলি দুইটা পেরামিটার নিতে পারে। একটা হচ্ছে , path or URL এবংঅন্যটা একটা কলব্যাক ফাঙ্কশন।

আমাদের ক্ষেত্রে,কন্ট্রোলার থেকে এক্সপোর্ট করা ফাঙ্কশন হচ্ছে কলব্যাক ফাঙ্কশন ,যার মধ্যে আমাদের বিসনেস লজিক আছে। এগুলো যেহেতু, কলব্যাক ফাঙ্কশন তাই কল করার দরকার হয় না। বিহাইন্ড দা সীন Express ফ্রেমওয়ার্ক এগুলোকে কল করে। আর path (API endpoint or URL) তো বুঝোই , যে লিংক এ আমরা বা ক্লায়েন্ট হিট করবে।

then,লাস্ট এ আমরা router অবজেক্ট কে এক্সপোর্ট করে দিয়েছি as userRouter নাম দিয়ে।

তুমি যখনি, অন্য কোথাও রাউটার ফাইল use করবা ,router এর পরিবর্তে userRouter বলে কল করবা। এই naming করাকে আবার, একটু ফেন্সি করে alias বলে। তবে এর সুবিধা হচ্ছে কোড রিডেবল করা।

Note: when you import this module in another file, you can use the userRouter alias to access the router object. This is a common pattern used to export and import modules in JavaScript.

#index.js:

finally আমাদের রাউটিং কে মেইন এন্ট্রি পয়েন্ট index.js কে জানাতে হবে ,

//index.js
import express, { json } from "express";
import dotenv from "dotenv";
import cors from "cors";
import cookieParser from "cookie-parser";
import { userRouter } from "./routes/userRoute.js";

dotenv.config();
const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());
app.use(cookieParser());
app.use(cors());

app.listen(PORT, () => {
  try {
    console.log(`Server is running on ${PORT}`);
  } catch (err) {
    console.log(err);
  }
});

app.use("/api", userRouter);

আমাদের আগের ইম্পোর্ট করা ফাইল গুলির সাথে নতুন যোগ হবে import { userRouter } from "./routes/userRoute.js" এটা, সব রাউটিং গুলোকে নিয়ে আসে।

এবং তুমি index এর লাস্ট এ app.use("/api", userRouter) userRoute use করে ফেলবা।

as সিম্পল as that ।

এবারে , তুমি তোমার ,কোডের দিকে খেয়াল করলে দেখবা আগের থেকে mach অর্গানাইজ আর ইনডেক্স.js একদম ক্লিন ।

যে কেও দেখেই বুজতে পারবে কি হচ্ছে।

Note: app.use হচ্ছে এক্সপ্রেস এর একটা মেথড যা, মাউন্ট ("mount" refers to attaching or associating) করে middleware functions or sub-applications স্পেসিফিক path এর উপর ডিপেন্ড করে।

example : app.use(cors()) এখানে দেখো cors middleware ফাঙ্কশন কল করছে তাই path লাগে নি । কিন্তু আমাদের ক্ষেত্রে userRouter হচ্ছে sub-applications বা http রিকোয়েস্ট হ্যান্ডলার তাই আমরা path বলেদিয়েছি app.use("/api", userRouter)

#Checking_The_Application:

তুমি এবারে চেক করে দেখতে পার ,এপ্লিকেশন ঠিকঠাক চলছে কিনা। সার্ভার ফোল্ডার টার্মিনাল এ ওপেন করে npm start কমান্ডদিলে সার্ভার রান হয়ে যাওয়ার কথা ।

//Output 
Server is running on 3000

#Roundup_What_We_Done:

চলো একনজরে দেখি কি কি করলাম :

You can take a look at my folder in the Image below:

    1. Create Configuration and Prisma Client:

      • Create a config folder.

      • Inside the config folder, create a file named prismaClient.js to set up the Prisma instance.

      1. Business Logic Controllers:

        • Create a controllers folder.

        • Inside the controllers folder, create a file named userController.js to handle business logic related to user data.

      2. Routing:

        • Create a routers folder.

        • Inside the routers folder, create a file named userRouter.js to define routing related to user endpoints.

      3. Link Components:

        • In the prismaClient.js file set up the Prisma instance and export it.

        • In the userController.js file, write the business logic for user-related operations using the Prisma instance.

        • In the userRouter.js file set up Express Router and link it to the appropriate controller functions.

        • In the index.js (entry point) file, import and use userRouter by app.use() method.

আশাকরি তোমার কাছে পরিষ্কার, ঘটনা কি ঘটছে।

#Conclusion:

তুমি হয়তো খেয়াল করছ, আমার সার্ভার ফোল্ডার এ apiTest.http নাম একটা ফাইল আছে।

এটা মূলত পোস্টম্যান এর মত কাজ করে । কিন্তু vs কোডে । REST Client নামে এক্সটেনশন রিকোয়েস্ট হ্যান্ডেল করে as ক্লায়েন্ট।

Name: REST Client Id: humao.rest-client Description: REST Client for Visual Studio Code Version: 0.25.1 Publisher: Huachao Mao VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=humao.rest-client

নিচের ইমেজ এ দেখ :

//apiTest.http
GET http://localhost:3000/api/users

###Post Request For Create User

POST http://localhost:3000/api/users
Content-Type:application/json

{
    "email":"tmdjishan2@gmail.com",
    "profile":{
        "name":"Tanvir Jishan"
    }
}

### Delete

DELETE http://localhost:3000/api/users/tmjishan2@gmail.com

###Update

PUT http://localhost:3000/api/users/tmjishan2@gmail.com
Content-Type: application/json

{
    "email":"tmjdishan@gmail.com"
}

#আউটপুট_ভিডিও : https://youtu.be/jpJt5GKgYe8

আশাকরি বুজতে পারছ।


Your interest is valued! Anticipate the upcoming segment for further insights. Feel free to follow for continued updates on my endeavors.

#devTj #tanvir_mehedi #Prisma #mernstack #javascript