Use Of Express Middleware in Bangla ⇾ Explain Backend Series

Use Of Express Middleware in Bangla ⇾ Explain Backend Series

Basic Backend Part 2

Learn in this Lesson :

এপর্যন্ত :

তুমি এখন পর্যন্ত শিখছ কিভাবে একটি nodejs এপ্লিকেশন সেটআপ করতে হয় ।এক্সপ্রেস ব্যবহার করে কত সহজে তুমি একটি সার্ভার রান করতে পারো এবং GET ও POST মেথড ব্যবহার করে ক্লায়েন্ট থেকে request নিয়ে আসতে বা response ব্যাক করতে পার । এছাড়া res ও req অবজেক্ট ব্যবহার করে ক্লায়েন্ট থেকে যে সকল ডাটা পাঠাইছে সেটা প্রোসেস করে মেমরি তে save করে রাখতে পার । যেটাকে তুমি inMemory বলে লিখছ।

এই সবগুলো প্রোসেস যে কোন ব্যাকএন্ড এপ্লিকেশন এ applicable । বলাযায় তুমি যত ব্যাকএন্ড এপ্লিকেশন দেখতেছ তারমধ্যে ৯০% এপ্লিকেশন এই প্রসেস ফলো করে হয়েথাকে । বাকি যে ১০% আছে ঐটা মনেকর বড় হইলে বুজবা ।ঐটা নিয়া মাথা ঘামাইয়া এখন লাভ নাই । আর তোমায় নিশ্চই তোমার কোন বড় ভাই/আপু বলছে, ডাটাবেস ছাড়া ব্যাকএন্ড হবে না !!!। হবে না সেটা ঠিক কিন্তু মজার ব্যাপার কি যান ? এপ্লিকেশন এর সাথে ডাটাবেস এর কোনো সম্পর্ক নেই । তুমি চাইলে ইনফরমেশন ,ডাটাবেস এ store না করেও এপ্লিকেশন চালাতে পার।এইযে তুমি নানান type এর logic লিখে ফেলতেছ ,এইটা করলে এটাহবে ,ওটা করলে এইটা ব্যাক যাবে , এটাকেই মূলত এপ্লিকেশন বলে ।কিন্তু যখনি এমন কনসেপ্ট চলে আসবে , যে ক্লায়েন্ট ডাটা দিচ্ছে সেটা ক্লায়েন্ট পরে ব্যবহার করবে আর তাই ডাটা রাখা দরকার কোথাও ,ঠিক তখন লাগবে ডাটাবেস।

আজকে কি শিখবা :

যা যা আগে শিখছ ঐটাকেই ঘঁষামাজা করে নতুন কিছু বানাবা আজকে । আরও একটু ঝকঝকে করবা । কয়েকটা নতুন জিনিস আসবে তবে ব্যাপারনা ধরে ফেলতে পারবা । নতুন টপিকের মধ্যে আজকে তুমি দেখবা :

  • Middelware
  • Project Structure
  • project

এই ৩টা কাজই করবা আজকে।

Middelware :

মিডলওয়ার কি ? এককথায় বলতে গেল middleware একটা ফাঙ্কশন ।কিন্তু কেমন ফাঙ্কশন ?ফাঙ্কশন তো অনেক ধরণের হয় । তুমি এর আগের পর্বে যে handler বানাইছ সেটাও তো একটা ফাঙ্কশন।কিন্তু প্রশ্নটা হল middleware কেমন ফাঙ্কশন ?

উত্তর একটাই middleware just একটা controller function ।

app.post("/books", (req, res) => {
  books.push(req.body);
  res.send(books);
});

উপরে কোড এ যে ফাঙ্কশন তুমি কালকে বানাইছিলা আর middleware, এদের মধ্যে basically তেমন কোনো পার্থক্য নেই ।

ধরো তুমি একটা pipeline বানাইলা Res->M1->M2->M3->Res

এখানে M দিয়ে তুমি middleware কে বুজবা । এইযে req ,m1,m2,m3,res এদের প্রত্যেকের same ক্ষমতা বা পাওয়ার ।এরা যে কেও চাইলেই রেসপন্স ব্যাক করতে পারে ।তুমি যদি চাও middelware না বানিয়ে শুধু res.send দিয়া রেসপন্স ব্যাক করবা সেটাও পারতা ।

তবে কেন তোমার middleware লাগবে ?

middleware এর কনসেপ্ট টা আসছে dry (do not repeat your self ) principle থেকে ।তুমি এমন অনেক কাজ করবা যা প্রত্যেকটা request এর জন্য same ভাবে করতে হবে।একই কোড বারবার লেখা লাগবে । বারবার একই কোড লেখা থেকে বাঁচার জন্য তুমি একটা কন্ট্রোলার ফাঙ্কশন বানাবা যেটা বারবার ব্যবহার করবা। এই reusable কন্ট্রোলারই মূলত middleware।এই কন্ট্রোলার ফাঙ্কশন টা তুমি চাইলে সব রিকোয়েস্ট এ ব্যবহার করতে পার,সিঙ্গেল একটা রিকোয়েস্ট এর সাথেও ব্যবহার করতে পার আবার একাধিক রিকোয়েস্ট এ ব্যবহার করতেপার ।কন্ট্রোল তোমার নিজের হাতেই থাকবে। এই এত এত কঠিন নাম middleware এইটা আসলে একটা কন্ট্রোলার ।

এই middleware তৈরী করার একটা signature আছে ।signature টা দেখতে নিচের কোডের মতো । আর এই middleware ফাঙ্কশন কখনো তুমি নিজে কল করবা না ।just রেফারেন্স পাস করে দিবা। মানে ,নাম বসাইয়া দিবা। call করার দায়িত্ব এক্সপ্রেস ফ্রেমওয়ার্কের। যেহেতু call করবে এক্সপ্রেস তাই ৩টা আর্গুমেন্ট দিয়া দিবে req,res,next । আর req ,res এর যত গুলো .property আছে সব এক্সপ্রেস অটোমেটিক্যালি push করে দিবে ,তুমি ব্যবহার করতে চাইলে করতে পারবা । বাকি থাকে next, এইটা জাস্ট একটা callback ফাঙ্কশন তুমি প্রয়োজন অনুযায়ী call করতে পার । নেক্সট নাম ই যে দিতে হবে এমন না তবে এটাই কনভেনশন ।একটা সাধারণ কন্ট্রোলার আর middleware এর মধ্যে পার্থক্য এই next function ।

এখন কথা হচ্ছে next ফাঙ্কশন কিভাবে একটা পার্থক্য create করতে পারে ?তুমি যদি একটা একটা middleware তৈরী কর আর next ফাঙ্কশন call না কর তবে পাইপলাইন এর পরের স্টেপ এ যাবেই না স্ট্যাক হয়ে বসে থাকবে ।

Res->M1->M2->M3->Res (M1 এ যদি next call না করি তবে M2 তে যাবে না )

middelware.png

//this is middleware
function xyz(req,res,next){
next()
}

//this is controller
function xyz(req,res,next){
res.send()
}

প্রত্যেকটা middleware ,res মধ্যে পার্থক্য হচ্ছে ,এদের প্রত্যেকের রেস্পন্সিবিলিটি আলাদা আলাদা ।

ধরো ক্লায়েন্ট Req তে রিকোয়েস্ট পাঠালো then Req সেই ডাটাকে M1 এর কাছে পাস করে দিলো । এখন M1 middleware চাইলে রিকোয়েস্ট Req এর ডাটা কে চেঞ্জ করতে পারবে এবং চেঞ্জ করে next ফাঙ্কশন call করে দিলে ডাটা M2 এর কাছে চলে যাবে।আর যদি M1 next ফাঙ্কশন কল না করে তবে পরবর্তী স্টেপ এ যাবে না । স্ট্যাক হয়ে বসে থাকবে। তবে যদি তুমি M1 এ next কল না করে res.send(),res.end(),res.json() এমন প্রপার্টি মেথড কল করো তবে রেসপন্স ব্যাক করে দিবে।

তাহলে কথাটা কি দাঁড়াল, হয় তুমি next কল করে পরের প্রসেস এ পাঠাবা either রেসপন্স ব্যাক করে দিবা।

রেসপন্স ব্যাক করলে সেটাকে কন্ট্রোলার ফাঙ্কশন বলবা । আর next কল করলে সেটাকে middleware বলবা।middleware যদি প্রসেস ফুলফিল করে তবে পরের middleware এ যাবে এবং modified ডাটা পাবে ।

এর আগে আমরা যে app.use(express.json()) ব্যবহার করছ সেটা একটা middleware । app.use ব্যবহার করে তুমি গ্লোবাল middleware ব্যবহার করবা ।

parctice :

তুমি আগে যা কোড করছ server.js ফাইল এ সব মুছে ফেল। তারপর নতুন করে express require করে সার্ভার চালাও । না দেখে করবা ,আগের কোড দেখবা না ।কোন route create করা ছাড়াই বাকি সব কোড লিখে সার্ভার রান করে দাও । দেখ, আমাদের এপ্লিকেশন টা চলছে ।

s.png

browser এ যাও এবং localhost:8000 url এ হিট করো তবে :

f.png

এমন টেক্সট পাবে। এর মানে টা দাঁড়াল তোমার সার্ভার রানিং কিন্তু রাউটার বানাও নাই ,আর তাই সে কিছু get করতে পারতেছে না ।তাহলে রাউটার বানাই ফেলো ।

Create Router & Middleware :

const express = require("express");

const app = express();

app.use(express.json());

app.get("/hello", (req, res, next) => {
  res.json({ message: "Hello" });
});

app.listen(8000, () => {
  console.log("Server Is Listening on Port 8000");
});

তোমায় যদি কেও এখন থেকে কন্ট্রোলার বা middleware বানাতে বলে তুমি চোখ বন্ধ করে

app.get("/hello", (req, res, next) => {
  res.json({ message: "Hello" });
});

কোডে দেখান signacher ফলো করবা । তো যেহেতু তুমি res.json দিছ ,তাই এটা নিঃসন্দেহে কন্ট্রোলার । browser এ গিয়া যদি url হিট করো localhost:8000/hello আউটপুট পাবা :

Screenshot from 2022-08-04 00-39-19.png

এখন ধরো তোমার দরকার , যখন কোন ক্লায়েন্ট রিকোয়েস্ট পাঠাবে ,তুমি চাও তোমার টার্মিনালে,কখন রিকোয়েস্ট আসছে ,এবং কোথেকে রিকোয়েস্ট আসছে সেটা log করে দেখাবে । মানে হচ্ছে একটা সিম্পল logger বানাতে হবে তোমায় ।এবং সেটা সব গুলো কন্ট্রোলার এর মধ্যে ব্যবহার করতে হবে ।

তাহলে কি করতে পার তুমি ?

app.get("/hello", (req, res, next) => {
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
  res.json({ message: "Hello" });
});

তেমন কিছুই না console.log() নিয়ে তার মধ্যে req.url দিয়া কোন url দিয়া রিকোয়েস্ট আসছে সেটা দেখতে পার ।req.method দিয়ে কি মেথড এ রিকোয়েস্ট আসছে সেটা জানতে পার। new Date() দিয়ে সময়টা জানতে পার রিকোয়েস্ট এর । আর সেটাকে স্ট্রিং এ কনভার্ট করতে পার।ব্যাস তোমার logger তৈরী।

ব্রাউসার এ গিয়া url হিট করলে টার্মিনালে আউটপুট আসবে :

Screenshot from 2022-08-04 00-57-52.png

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

তার থেকে তুমি যদি এখানে একটা middleware create কর সেটা সহজ হবে । কিভাবে ?নিচে কোডে দেখো :

const simpleLogger = (req, res, next) => {
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
};

middleware create হল simpleLogger নামে। কিন্তু এই middleware কিভাবে কোথায় ব্যবহার করবো ?

answer সহজ তুমি দুই ভাবে middleware ব্যবহার করতে পার। Global and Local ।

Local Middleware :

তোমার কয়েকটা স্পেসিফিক রিকোয়েস্ট বা route যে middleware টা দরকার। সবগুলো না , just কিছু সংখক route এর দরকার । সেটাই Local Middleware ।এই এতুটুকুই ।

Use of Local Middleware :

app.get("/hello",simpleLogger, (req, res, next) => {  
  res.json({ message: "Hello" });
});

তুমি যে route বানাইছ সেই route এর path /hello এবং কন্ট্রোলার (req, res, next) => এই দুই এর মাঝে middleware বসবে। আর পাশাপাশি অনেক অনেক middleware বসতে পারে ।ওহ হ্যা এই middleware তুমি call করবা না ।call করবে তোমার হয়ে express।

এখন যদি url হিট করো দেখব সে স্ট্যাক হয়ে ঘুরতেছে ঘুরতেছে ।

কেন ঘুরতেছে ?

কারণ তুমি যে middleware বানাইছ simpleLogger সেখানে তো next call ই করনি ?আগেই বলছি next কল না করলে সেটা পরের middleware বা রেসপন্স এ যাবে না । কথা ১০০% মিলে গেছে । তাহলে এখন next কল করে দাও । কোথায় নেক্সট কল করবা ?middleware এর মধ্যে । simpleLogger এ ।

const simpleLogger = (req, res, next) => {
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
  next();
};

এবার ফারফেক্টলি কাজ করবে ।

Whitout Middleware Route :

এবার তুমি একটা হোম route বানাও ।middleware ব্যবহার ছাড়া ।

app.get("/", (req, res, next) => {
  res.json({ message: "This Is Home" });
});

localhost:8000 url এ হিট কর দেখবা টার্মিনালে আমাদের logger দেয়নি ।কারণ তুমি তো এখানে middleware ব্যাবহারী কর নি।সরাসরি রেসপন্স ব্যাক করে দিয়েছে ।

এটাই হচ্ছে লোকাল middleware এর মূল কাজ ।যেখানে লাগবে use করব না লাগলে করব না।

কিন্তু তুমি এমন ভাবলে যে আমার সব route এ middleware কাজ করবে ।সব রিকোয়েস্ট এর জন্য logger চাই ,তখনি আসে গ্লোবাল middleware এর কনসেপ্ট ।

Final Code server.js

const express = require("express");

const app = express();

app.use(express.json());

const simpleLogger = (req, res, next) => {
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
  next();
};

app.get("/hello", simpleLogger, (req, res, next) => {
  res.json({ message: "Hello" });
});

app.get("/", (req, res, next) => {
  res.json({ message: "This Is Home" });
});

app.listen(8000, () => {
  console.log("Server Is Listening on Port 8000");
});

Global Middleware :

সিম্পল ভাবে বললে যে middleware টা তোমার প্রত্যেকটা route এ প্রত্যেকটা রিকোয়েস্ট এ দরকার সেটাই গ্লোবাল middleware ।

Use of Global Middleware :

যখনি তুমি কোন middleware কে গ্লোবালি ব্যবহার করবা express এর app.use method ব্যবহার করবা । use method তোমায় ওই ক্ষমতা দেয় ,যার মাধ্যমে middleware ,router ,handler এমন যা খুশি তুমি ব্যবহার করতে পার।

এখন তুমি চাচ্ছ তোমার simpleLogger middleware কে use করবা এবং এর মাধ্যমে সব গুলো রিকোয়েস্ট এর log বের করবা । সিনটেক্স টা হবে

app.use(simpleLogger)

code explain করলে হয় ,app তোমার মধ্যে যে use মেথড আছে সেখানে আমি simpleLogger ব্যবহার করতে চাই ।thats it । আর সেই same কথা middleware তো কল/invoke করতে হয়না । কল করে দেয় এক্সপ্রেস ।

app.use ব্যবহার করে কোন middleware use করার মানে হচ্ছে, globally middleware কে রেজিস্টার করা। সে ক্ষেত্রে locally আর middleware use করার দরকার নাই ।

const express = require("express");

const app = express();

app.use(express.json());

const simpleLogger = (req, res, next) => {
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
  next();
};

app.use(simpleLogger);

app.get("/hello", (req, res, next) => {
  res.json({ message: "Hello" });
});

app.get("/", (req, res, next) => {
  res.json({ message: "This Is Home" });
});

app.listen(8000, () => {
  console.log("Server Is Listening on Port 8000");
});

Output Terminal

/hello - GET -2022-08-04T16:46:25.992Z log ঠিকঠাক ভাবেই দিচ্ছে ।

Practice Middleware :

তোমায় একটা টাস্ক দিয়ে দিচ্ছি চেষ্টা করো নিজে নিজে করতে । বুঝেবুঝে করতে ।

একটা medileware বানাও যেটা ক্লায়েন্ট এর query অনুযায়ী bad রিকোয়েস্ট অথবা মেসেজ জেনারেট করবে ।ধরো যদি query string এ 404 হয় তবে বলবে bad request আর যদি query string না থাকে তাহলে যে route রেসপন্স এ যে মেসেজ দেয়ার কথা তাই দিবে ।

SOLUTION CODE AND OUTPUT :

const express = require("express");

const app = express();

app.use(express.json());

const simpleLogger = (req, res, next) => {
  if (req.query.bad == 404) {
    res.json({ message: "404 Bad Request" });
  }
  console.log(`${req.url} - ${req.method} -${new Date().toISOString()}`);
  next();
};

app.use(simpleLogger);

app.get("/hello", (req, res, next) => {
  res.json({ message: "Hello" });
});

app.get("/", (req, res, next) => {
  res.json({ message: "This Is Home" });
});

app.listen(8000, () => {
  console.log("Server Is Listening on Port 8000");
});

Screenshot from 2022-08-05 01-22-35.png

Project Structure

তুমি এখন যে প্রজেক্ট Structure এ কাজ করছ,এটাকে বলাহয়েথাকে monolithic architecture । কোড মেনেজ করার জন্য একটা প্রজেক্ট কে সুন্দর ভাবে সাজান খুবই গুরুত্বপূর্ণ । এতে করে কোড ক্লিন হয় ।পরবর্তীতে কোন চেঞ্জ আনলে তা সহজে ধরে ফেলা যায় ।

monolithic architecture বলতে সব কোড গুলো একই জায়গায় রেখে যে তুমি ডেভেলপমেন্ট করতেছ এটাই ।মানে একটা ফোল্ডার এ রেখে বাইরে থেকে কিছু আসছে না ।আপাতত এইটুকু জানলেই চলবে ।

Folder Structure

তুমি এখন আমার সাথে সাথে কিছু ফোল্ডার বানাবে তোমার প্রজেক্ট ফোল্ডার এ । তাহলে শুরু করাযাক :

আমি আমার প্রজেক্ট ফোল্ডার basicExpress এ বানাচ্ছি ।তুমি তোমার main ফোল্ডারে বানাও

  • app (এখানে এপ্লিকেশন এর database connection ,app ফাইল ,global route এসব থাকবে )

  • error (errors হ্যান্ডেল / কাস্টম error এর জন্য )

  • routes (সমস্ত routes গুলো এখানে থাকবে )

  • models (যতগুলো ডাটামডেল রয়েছে সেগুলো এখানে থাকবে )

  • controller (এপ্লিকেশন এর কন্ট্রোলার থাকবে এখানে )

  • service (সাধারণত ডেটাবেস এর সাথে কমুনিকেশন করে থাকে সার্ভিস )

  • middleware (সমস্ত কাস্টম middleware থাকবে )

  • utils (উটিলিটিস ফাইলস এর জন্য )

  • db (ডাটাবেস এর মক )

  • config (কনফিগারেশন এর জন্য config )

  • log (সমস্ত লগস গুলো এখানে রাখা হয় )

ঠিক এভাবেই ফোল্ডার স্ট্রাকচার হয়ে থাকে মনোলিথিক আর্কিটেকচার এর ।

Screenshot from 2022-08-05 02-06-39.png

so এটাই তোমার বয়লারপ্লেট কোড ।এখানে প্রয়োজন অনুযায়ী ফোল্ডার অ্যাড হতে পারে ।ফাইল অ্যাড হতে পারে । তবে একটা মনোলিথিক আর্কিটেচার ফোল্ডার স্ট্রাকটার এমন হয় ।

পরবর্তী লেকচার এ তুমি বেসিক প্রজেক্ট নিয়ে কাজ করবা । আপাতত এই পর্যন্ত ।

কোথাও কোন confusion হলে কমেন্ট করেতে ভুলনা

Everything we do is practice for something greater than where we currently are. Practice only makes for improvement. – Les Brown.