React Bangla Logo
Reactবাংলা

Axios দিয়ে HTTP Request হ্যান্ডেলিং— সম্পূর্ণ বাংলা গাইড

Axios দিয়ে API handling শিখুন। একদম বেসিক থেকে শুরু করে Instance, Interceptors, Error Handling এবং একটি সম্পূর্ণ CRUD প্রজেক্টের হাতে-কলমে টিউটোরিয়াল।

Axios দিয়ে HTTP Request হ্যান্ডেলিং — একটি সম্পূর্ণ বাংলা রিসোর্স

এই পোস্টে আমরা শিখবো—Axios দিয়ে API Handling। Frontend অ্যাপ্লিকেশনকে Backend API-এর সাথে connect করতে GET, POST, PUT, DELETE ইত্যাদি HTTP request করতে হয়। আর এই কাজটিকে আরও সহজ ও clean করতে আমরা ব্যবহার করতে পারি Axios। fetch() API-এর তুলনায় Axios-এর syntax সহজ, automatic JSON parsing করে এবং error handling-ও সহজ।

Table 6.1: Tools in the React Ecosystem

টুল / টেকনোলজিকেন দরকার?
React Hook FormForm- এর প্রতিটি input field আলাদাভাবে state দিয়ে ম্যানেজ না করে, কম কোডে validation, error message, আর submit হ্যান্ডেল করা যায়— এর বড় ফর্মেও performance ভালো থাকে।
React RouterSingle Page Application- এ Multi page feel দেয়। (/login, /signup, /dashboard) পেজ রি-লোড ছাড়া URL অনুযায়ী নেভিগেট করা যায়।
Redux ToolkitApplication- এ কিছু ক্ষেত্রে প্রায় প্রতিটা Component জুড়ে একই data শেয়ার করতে হয় (যেমন user info, cart) তখন আমাদের data centralize এ করে রাখার জন্য global একটি state manage করতে হয়- Redux Toolkit এ দিয়ে আমরা গ্লোবাল একটি স্টেট ম্যানেজ করতে পারি, এ RTK Query দিয়ে সেই data সহজে API থেকে fetch, cache করা যায়।
React Queryএটি ক্লায়েন্ট থেকে সার্ভারে নেটওয়ার্ক কল পরিচালনা data fetch, cache, আর automatically sync (background refetch, stale data update) করার জন্য— বারবার loading / error state এ নিজ হাতে লিখতে হবে না।
Firebase AuthUser signup / login (email-password, Google login) কয়েক লাইনের কোডেই সেট আপ করা যায়, নিজে backend থেকে পুরো authentication এ সিস্টেম বানাতে হয় না।

ডেভেলপারদের জীবনে সার্ভারের সাথে ডেটা আদান-প্রদান করা খুব সাধারণ এবং গুরুত্বপূর্ণ কাজ। এই গাইডে আমরা Axios একদম বেসিক থেকে শুরু করে instance, interceptors, JWT auth, auto refresh-token, এবং facebook profile Feed সম্পূর্ণ CRUD প্রজেক্ট বানিয়ে শিখবো।

ধরুন, আপনি একটা React অ্যাপ বানাচ্ছেন- একটি Feed; যেখানে আপনাকে ইউজার পোস্টগুলো দেখাতে হবে, নতুন পোস্ট তৈরি করতে হবে, লাইক-কমেন্ট করতে হবে। এই সব কাজের জন্য সার্ভারের সাথে কথা বলতে হয়— ডেটা পাঠাতে হয়, ডেটা নিয়ে আসতে হয়। এই কাজটাকে বলে HTTP Request।

HTTP Request করার জন্য JavaScript-এ fetch আছে, কিন্তু Axios ব্যবহার করা বেশি সুবিধাজনক। কারণ- Axios অনেক কাজ নিজেই করে দেয়: JSON পার্স করা, error সহজে ধরা, request যাওয়ার আগে বা পরে কিছু করা (Interceptors)।

আমরা এই গাইডটি দুটো ভাগে ভাগ করব:

  • Part 1 (সেকশন ১-৭): Axios-এর বেসিক — একটা mini json-server backend দিয়ে হাতে-কলমে http request, response, error handling (server error vs network error), CRUD (create/update/delete), instance, interceptors এবং CORS সমাধান।
  • Part 2 (সেকশন ৮-৩১): থাকবে একটি রিয়েল প্রজেক্ট fb-feed — Facebook Profile Feed — JWT Auth, Auto Refresh token, Post CRUD, Profile System, Avatar Upload — সব হাতে-কলমে করে দেখাবো।

Part 2: Facebook Clone: Deshi Book Complete Project with Context API + Axios

১. Axios কী এবং কেন ব্যবহার করবো?

Axios হলো একটি Promise-based HTTP Client। যা ব্রাউজার এবং Node.js উভয় পরিবেশে ডেটা আনা-নেয়ার (API Call) জন্য ব্যবহৃত হয়। এটি সার্ভার থেকে ডেটা আনা (GET) বা ডেটা পাঠানো (POST) অত্যন্ত সহজ করে দেয়।

একটা গল্প দিয়ে বোঝাই। আপনি রেস্টুরেন্টে বসে আছেন। Waiter (Axios) আপনার অর্ডার (request) নিয়ে রান্নাঘরে (server) যায়, রান্না হলে খাবার (response) নিয়ে ফেরত আসে। এই পুরো প্রক্রিয়াটাকে Axios পরিচালনা করে।

১.১ কেন fetch-এর বদলে Axios?

Table 6.2: fetch বনাম axios

বিষয়fetchaxios
JSON পার্সres.json() আলাদা call করতে হয়অটোমেটিক করে দেয়
Error ধরাশুধু network error, 4xx / 5xx ধরে নাসব error সহজে ধরে
Interceptorsনেইআছে — request/response
Browser + Node.jsশুধু Browserদুটোতেই কাজ করে

4xx vs 5xx http response status code

HTTP status code হলো server-এর response-এ থাকা একটা নাম্বার, যেটা বলে দেয় request-টা কেমন গেলো।

4xx (Client Error): ভুলটা client/request-এর দিক থেকে— যেমন ভুল URL, missing data, বা auth ছাড়া access করার চেষ্টা। উদাহরণ: 404 Not Found, 401 Unauthorized, 400 Bad Request।

5xx (Server Error): request ঠিকই ছিল, কিন্তু server-এর দিকে সমস্যার কারণে fulfil করতে পারেনি। উদাহরণ: 500 Internal Server Error, 503 Service Unavailable।

সংক্ষেপে: 4xx = তুমি ভুল করেছো, 5xx = server ভুল করেছে।


২. প্র্যাকটিসের জন্য একটা ছোট্ট Backend বানিয়ে নিব — json-server

Axios শিখতে একটা আসল সার্ভার লাগবে। তাই আমরা json-server দিয়ে কয়েক মিনিটেই একটা ফেক (fake) কিন্তু সত্যিকারের REST API বানিয়ে নিব।

মনে রাখুন এই json-server বানিয়ে নিব, শুধু Part 1-এর Axios বেসিক প্র্যাকটিসের জন্য। Part 2-এর রিয়েল project-এর জন্য আমরা একটি সত্যিকারের backend-ই ব্যবহার করব।

২.১ json-server ইনস্টল করা

VS Code এ axios-practice নামে একটি ফোল্ডার বানিয়ে ওপেন করুন। টার্মিনাল ওপেন করে নিচের কমান্ড চালান। স্টেবল ভার্সন 0.17.4 রাখাই ভালো। প্রথমে npm init -y তারপর,

npm init -y
npm install -g json-server@0.17.4

অথবা,

# ১. রিপোজিটরি ক্লোন করুন
git clone https://github.com/codedbymojnu/react-book

# ২. ফোল্ডারে ঢুকুন
cd react-book

# ৩. সঠিক ব্রাঞ্চে switch করুন
git checkout 6.1-axios-mock

# ৪. 6.1-axios-mock টার্মিনাল খুলে dependency ইনস্টল করুন
npm i

# ৫. সার্ভার চালান
npm run dev

২.২ db.json ফাইল বানানো

একটা db.json নামে ফাইল বানান, ভেতরে কিছু ফিগার ৬.১ এর মতো করে ডামি / মক ডেটা রাখুন:

Figure 6.1

{
  "posts": [
    {
      "id": "1",
      "title": "প্রথম পোস্ট",
      "body": "json-server দিয়ে তৈরি প্রথম পোস্ট।"
    },
    {
      "id": "2",
      "title": "দ্বিতীয় পোস্ট",
      "body": "Axios দিয়ে এই ডেটা fetch করা হবে।"
    }
  ],
  "comments": [{ "id": "1", "postId": "1", "text": "সুন্দর পোস্ট!" }]
}

সবকিছু ঠিক ঠাক থাকলে আমাদের সার্ভার http://localhost:8000 পোর্টে চলবে। এই টার্মিনাল ট্যাব পুরো টিউটোরিয়াল জুড়ে খোলা রাখুন।

২.৩ সার্ভার চালু করা

json-server --watch db.json --port 8000

Figure 6.2: Mock Server Start

PS D:\products\react-book> npm run dev

> 6.1-mock-server@1.0.0 dev
> json-server --watch db.json --port 8000

  \{^_^}/ hi!

  Loading db.json
  Done

  Resources
  http://localhost:8000/posts
  http://localhost:8000/comments

  Home
  http://localhost:8000

অথবা npm run dev দিয়ে সার্ভার চালাতে চাইলে package.json file এ নিচের মতো করে scripts মডিফাই করে নিন।

{
  "license": "ISC",
  "author": "react-bangla",
  "type": "commonjs",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "json-server --watch db.json --port 8000"
  }
}

সার্ভার চালু হলে টার্মিনালে http://localhost:8000 ঠিকানা দেখাবে। ব্রাউজারে গিয়ে ওই লিংকে চেক করুন — posts আর comments ডেটা JSON আকারে দেখাচ্ছে কিনা।

২.৪ json-server - এর API Routes চেনা

json-server আপনার db.json-এর প্রতিটা key-কে automatically একটা REST resource বানিয়ে দেয়। সব HTTP method (GET, POST, PUT, PATCH, DELETE) সাপোর্ট করে, আর http বা https — দুটো দিয়েই request পাঠানো যায়:

Table 6.3: Our Mock Server Endpoints

MethodRoute/endpointকাজ
GET/postsসব পোস্ট দেখা
GET/posts/1নির্দিষ্ট একটা পোস্ট দেখা
GET/posts/1/commentsওই পোস্টের সব কমেন্ট দেখা
GET/comments?postId=1query দিয়ে filter করে কমেন্ট আনা
POST/postsনতুন পোস্ট তৈরি
PUT/posts/1পুরো পোস্ট replace করা
PATCH/posts/1পোস্টের অংশবিশেষ আপডেট
DELETE/posts/1পোস্ট ডিলিট করা

Part 1 জুড়ে, আমরা এই posts resource-টাই ব্যবহার করবো।

Frontend Ready করি:

আশা করছি, আপনারা জানেন কিভাবে vite দিয়ে একটি রিঅ্যাক্ট অ্যাপ্লিকেশন সেটআপ করতে হয়। আপনি react-book রিপোজিটরি ক্লোন করে, সঠিক ব্রাঞ্চে (git checkout 6.1-axios-mock) চেকআউট করলে সেখানে frontend নামে একটি ফোল্ডার পাবেন। frontend ফোল্ডারের সবকিছু ডিলেট করে দিন। টার্মিনালে নিচের কমান্ডগুলো ধারাবাহিকভাবে execute করুন।

npm create vite@latest

আপনাকে কিছু প্রশ্ন করবে, প্রজেক্টের নাম দিন- frontend, ফ্রেমওয়ার্ক সিলেক্ট করুন- React (কি বোর্ডের ডাউন এরো প্রেস করে যান), ভেরিয়েন্ট সিলেক্ট করুন- JavaScript, এরপর ESLint, এরপর Yes সিলেক্ট করে Enter প্রেস করে দিন। সবকিছু ঠিক থাকলে আমাদের প্রোজেক্ট সাকসেস ফুলি http://localhost:5173/ পোর্টে চলবে।

PS D:\products\react-book> npm create vite@latest
◇  Select a framework:
│  React
◇  Select a variant:
│  JavaScript
◇  Which linter to use?
│  ESLint
◇  Install with npm and start now?
│  Yes
◇  Scaffolding project in D:\products\react-book\frontend...

Tailwind CSS সেটআপ

আমরা স্টাইলিংয়ের জন্য Tailwind CSS ব্যবহার করবো — একটি utility-first CSS framework, যেখানে প্রতিটা class একটা নির্দিষ্ট CSS property নিয়ন্ত্রণ করে।

npm install tailwindcss @tailwindcss/vite

vite.config.js file আপডেট করুন:

import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [react(), tailwindcss()],
});

src/index.css-এ Tailwind import করুন:

@import "tailwindcss";

৩. প্রথম Request — Data Read করব (GET)

আপনি আগে Ensure করুন যে, আমাদের Mock Server http://localhost:8000 পোর্টে রানিং আছে। না হলে আর একটি নতুন টার্মিনাল খুলে মক সার্ভার চালু করে নিন। ধরুন, আগে আপনার React কম্পোনেন্ট একটা লোকাল db.js ফাইল থেকে ডেটা import করে দেখাতেন। এখন সেটা বদলে আসল API (আমাদের json-server) থেকে ডেটা আনতে হবে। Frontend Folder থেকে Axios install করুন।

npm install axios

৩.১ State সেটআপ করা

আপনার প্রোজেক্টের App.css file টি ডিলেট করে দিন। App.jsx এ সবার আগে ডেটা আর error রাখার জন্য state বানান:

import { useState, useEffect } from "react";
import axios from "axios";

function App() {
  const [posts, setPosts] = useState([]); // শুরুতে খালি array
  const [error, setError] = useState(null); // এরর মেসেজ রাখার জন্য

posts-কে খালি array ([]) দিয়ে শুরু করা হচ্ছে, কারণ শুরুতে সার্ভার থেকে এখনো কোনো ডেটা আসেনি।

৩.২ useEffect-এর ভেতরে সরাসরি async কেন লেখা যায় না?

useEffect-এর callback function-কে সরাসরি async বানানো যায় না। তাই ভেতরে একটা আলাদা async function বানিয়ে সেটাকে কল করতে হয়:

useEffect(() => {
  const fetchPosts = async () => {
    // এখানে axios call হবে
  };

  fetchPosts(); // ফাংশনটাকে সাথে সাথে কল করা হচ্ছে
}, []); // খালি array মানে এটা শুধু একবার, component mount হওয়ার সময় রান করবে

৩.৩ axios.get() দিয়ে ডেটা আনা

কম্পোনেন্ট রেন্ডার হওয়ার পর, useEffect রান হয়। এখন, আমরা একটি ফাংশন বানিয়ে ঐ ফাংশন কল করে ডেটা নিয়ে আসব। অবশ্যই ফাংশন কল করব, useEffect এর ভেতর থেকে কারণ এটা সাইড-ইফেক্ট। প্রশ্ন থাকলো, ফাংশনটি useEffect-এর বাইরে লিখে, useEffect-এর ভেতরে শুধু কল করে দিলেই তো হতো। কিন্তু এটা কেন বেটার প্র্যাকটিস না?

useEffect(() => {
  const fetchPosts = async () => {
    try {
      const response = await axios.get("http://localhost:8000/posts");
      // Axios সরাসরি response.data-তে রেজাল্ট দিয়ে দেয়
      if (response && response.data) {
        setPosts(response.data);
      }
    } catch (err) {
      setError(err.message);
      console.error("API Call Error:", err);
    }
  };

  fetchPosts();
}, []);

সাধারণ fetch ব্যবহার করলে এখানে আরেকটা json() কল লাগত (const data = await res.json())। Axios সেটা নিজেই করে দেয়— response.data-তেই আসল ডেটা পাওয়া যায়। এখানে আমরা এরোর হ্যান্ডেল status / statusText দিয়েও করতে পারি।

৩.৪ UI-তে ডেটা এবং এরর দেখানো

সার্ভার বন্ধ রেখে test করুন — error দেখাবে। সার্ভার চালু রেখে test করুন — পোস্ট লিস্ট দেখাবে। দুই ধরনের error ঠিক কীভাবে আলাদা করে ধরতে হয়, সেটা সেকশন ৪-এ বিস্তারিত দেখবো। নিচের ছবিতে UI তে পোস্টগুলো, আর এরোর পাইলে তা দেখানোর জন্য কোড শেয়ার করেছি। সেটা দেখে দেখে টাইপ করে নিন।

return (
  <div className="max-w-2xl mx-auto p-5">
    <h1 className="text-2xl font-bold mb-5">API Request with Axios</h1>

    {error && (
      <div className="bg-red-100 text-red-600 p-3 rounded mb-4">
        Error: {error}
      </div>
    )}

    <div className="space-y-4">
      {posts.map((post) => (
        <div key={post.id} className="bg-white p-4 rounded-lg shadow border">
          <div className="flex items-center gap-3 mb-3">
            <div className="w-10 h-10 rounded-full bg-gray-300"></div>

            <div>
              <h3 className="font-semibold">React Bangla</h3>
              <p className="text-xs text-gray-500">Just now</p>
            </div>
          </div>

          <h2 className="font-semibold mb-2">{post.title}</h2>
          <p className="text-gray-600">{post.body}</p>
        </div>
      ))}
    </div>
  </div>
);

৩.৫ Response Object-এর ভেতরে কী কী থাকে?

const response = await axios.get("http://localhost:8000/posts");
response.data; // ডেটা — সাধারণত এটাই লাগে
response.status; // HTTP status code: 200, 201, 404, 500
response.statusText; // "OK", "Created" ইত্যাদি
response.headers; // Response headers
response.config; // যে config দিয়ে request করা হয়েছিল

৩.৬ Request Customize করা — Config Object (Advanced)

GET ছাড়াও আরো অনেক কিছু customize করা যায়। এই সেকশনটি আপনারা চাইলে পরে পড়তে পারেন।

const config = {
  url: "/posts",
  method: "get",
  baseURL: "http://localhost:8000",
  // সব URL-এর আগে যুক্ত হবে
  headers: {
    "Content-Type": "application/json",
    Authorization: "Bearer your-token-here",
  },
  params: { page: 1, limit: 10 },
  // URL-এ query string যোগ হবে: /posts?page=1&limit=10
  timeout: 10000, // কত millisecond পরে request cancel হবে
  responseType: "json", // 'json', 'blob', 'text', 'arraybuffer'
};

// আমরা কনফিগ দিয়েও ইউজ-ইফেক্ট হুকে কল করে ডাটা নিয়ে আসতে পারি।

axios(config).then((res) => console.log(res.data));

৪. Error Handling — বেসিক থেকে অ্যাডভান্স

৪.১ তিন ধরনের এরর

catch (error) {
  if (error.response) {
    // সার্ভার response দিয়েছে, কিন্তু 4xx বা 5xx status সহ
  } else if (error.request) {
    // Request পাঠানো হয়েছে, কিন্তু কোনো response আসেনি
  } else {
    // Request বানানোর সময়ই কিছু ভুল হয়েছে
  }
}

৪.২ সার্ভার এরর বনাম নেটওয়ার্ক এরর

err.response আছে কিনা চেক করেই বোঝা যায় error টা কোন ধরনের। রেসপন্সে আসা এরোর সাধারণত ২ ধরনের হবে। ১। সার্ভার এরোর ২। ক্লাইন্ট এরোর

নিচের ছবির কোডটা খেয়াল করুন।

try {
  const res = await axios.get("http://localhost:8000/posts");
  setPosts(res.data);
} catch (err) {
  if (err.response) {
    // err.response থাকা মানে সার্ভার একটা রেসপন্স পাঠিয়েছে,
    // কিন্তু সেটা ভুল status (যেমন 404) নিয়ে এসেছে
    setError(`সার্ভার এরর: ${err.response.status} ${err.response.statusText}`);
  } else {
    // err.response নেই মানে request-ই সার্ভার পর্যন্ত পৌঁছায়নি
    // (Network Error — সার্ভার বন্ধ, বা ইন্টারনেট নেই)
    setError("সার্ভারের সাথে যোগাযোগ করা যাচ্ছে না।");
  }
}
  • URL ভুল দিলে (যেমন route আছে /posts, কিন্তু ভুল করে /post লিখলে) → err.response পাওয়া যাবে, status হবে 404।
  • সার্ভার বন্ধ থাকলে → err.response থাকবে না, এটা Network Error।

৪.৩ Dynamic Error Message বানানো

err.response.status আর err.response.statusText ব্যবহার করে ইউজারকে নির্দিষ্ট মেসেজ দেখানো যায়:

setError(
  err.response
    ? `${err.response.status}-${err.response.statusText}`
    : "নেটওয়ার্ক এরর — সার্ভার সাড়া দিচ্ছে না।",
);

৪.৪ Reusable Error Helper Function

একটা helper function রেখে দিলে পুরো প্রজেক্টের সব জায়গায় কাজে লাগবে। নিচের getFriendlyErrorMessage হেল্পার ফাংশনটি দেখুন। আপনার কাজ হলো- দেখে দেখে টাইপ করা, কোনো কপি-পেস্ট নয়।

function getFriendlyErrorMessage(error) {
  if (!error.response) {
    return "ইন্টারনেট কানেকশন বা সার্ভার সমস্যা। একটু পরে চেষ্টা করুন।";
  }
  const status = error.response.status;
  const msg = error.response.data?.error || error.response.data?.message;

  switch (status) {
    case 400:
      return msg || "Request-এ কিছু ভুল আছে।";
    case 401:
      return "লগইন করা নেই বা session শেষ।";
    case 403:
      return "এই কাজের অনুমতি নেই।";
    case 404:
      return "যা খুঁজছেন তা পাওয়া যায়নি।";
    case 500:
      return "সার্ভারে সমস্যা। একটু পরে চেষ্টা করুন।";
    default:
      return "কিছু একটা ভুল হয়েছে।";
  }
}

৫. ডেটা তৈরি, আপডেট ও ডিলিট করা (CRUD-এর বাকি অংশ)

এতক্ষণ শুধু Read (GET) করার http Request দেখলাম। এবার post Create, Update আর Delete করা শিখবো।

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

আমাদের কম্পোনেন্টগুলো হবে: ১। পোস্ট লিস্ট ২। এড পোস্ট ইডিটর

(আমরা একটি মক ফেসবুক ফিড প্রোজেক্ট বানাবো প্রথমে)

পোস্ট আপডেটে যাওয়ার আগে, নিচের স্ক্রিনশটগুলোর সাথে আপনার কোড মিলিয়ে নিতে পারেন। নিচে App.jsx ও PostList.jsx কোড আপনাদের সাথে শেয়ার করলাম।

App.jsx Screenshot

import axios from "axios";
import { useEffect, useState } from "react";
import PostList from "./components/PostList";
import { getFriendlyErrorMessage } from "./utils";

export default function App() {
  const [posts, setPosts] = useState([]);
  const [error, setError] = useState("");

  useEffect(() => {
    async function fetchPosts() {
      try {
        const response = await axios.get("http://localhost:8000/posts");
        if (response.status === 200) {
          setPosts(response.data);
        }
      } catch (error) {
        setError(getFriendlyErrorMessage(error));
      }
    }

    fetchPosts();
  }, []);

  return (
    <div className="max-w-2xl mx-auto p-5">
      <h1 className="text-2xl font-bold mb-5">API Request with Axios</h1>

      {error && (
        <div className="bg-red-100 text-red-600 p-3 rounded mb-4">
          Error: {error}
        </div>
      )}

      <PostList posts={posts} />
    </div>
  );
}

পোস্ট লিস্ট কম্পোনেন্টটি এর স্ক্রিনশট দেখে নিন:

export default function PostList({ posts }) {
  return (
    <div className="space-y-4">
      {posts.length > 0
        ? posts.map((post) => (
            <div
              key={post.id}
              className="bg-white p-4 rounded-lg shadow border"
            >
              <div className="flex items-center gap-3 mb-3">
                <div className="w-10 h-10 rounded-full bg-gray-300"></div>

                <div>
                  <h3 className="font-semibold">React Bangla</h3>
                  <p className="text-xs text-gray-500">Just now</p>
                </div>
              </div>

              <h2 className="font-semibold mb-2">{post.title}</h2>
              <p className="text-gray-600">{post.body}</p>
            </div>
          ))
        : "No Post Found"}
    </div>
  );
}

৫.১ নতুন ডেটা তৈরি করা (Create / POST)

const handleAddPost = async (title, body) => {
  try {
    const newPost = {
      id: Date.now().toString(),
      title,
      body,
    };

    const { data } = await axios.post("http://localhost:8000/posts", newPost);

    setPosts((prevPosts) => [...prevPosts, data]);
  } catch (err) {
    setError(getFriendlyErrorMessage(err));
  }
};

handleAddPost-কে async করা হয়েছে, কারণ ভেতরে await axios.post(...) ব্যবহার হচ্ছে। POST request-এ দ্বিতীয় argument হিসেবে যে ডেটা পাঠাতে চান, সেটা যায়।

এড পোস্ট দেখানোর জন্য UI আপডেট করি:

এড পোস্ট ইডিটর কম্পোনেন্ট বানিয়ে নিন, এখানে পোস্ট নামে একটি লোকাল স্টেট নিবেন। যেটা দিয়ে ইনপুট, এবং টেক্সট এরিয়াকে আপনি কন্ট্রোল করবেন; হ্যান্ডেল চেঞ্জ ফাংশন দিয়ে। এবং ফর্ম অন সাবমিটে handleAddPost ফাংশনকে পোস্ট প্যারামিটার হিসেবে পাঠিয়ে কল করে দিবেন।

return (
  <div className="bg-white border rounded-lg p-4 shadow-sm">
    <div className="flex gap-3">
      <div className="w-10 h-10 rounded-full bg-gray-300"></div>
      <form onSubmit={handleSumitPost}>
        <div className="flex-1 space-y-3">
          <input
            type="text"
            name="title"
            placeholder="Post title..."
            className="w-full border rounded p-2"
            value={post.title}
            onChange={handleChange}
          />

          <textarea
            rows="4"
            name="body"
            placeholder="What's on your mind?"
            className="w-full border rounded p-2 resize-none"
            value={post.body}
            onChange={handleChange}
          />

          <div className="text-right">
            <button
              type="submit"
              className="bg-blue-600 text-white px-5 py-2 rounded hover:bg-blue-700"
            >
              Post
            </button>
          </div>
        </div>
      </form>
    </div>
  </div>
);

App.jsx এ, AddPostEditor ইমপোর্ট করে, এর মধ্যে handleAddPost কে প্রোপস হিসেবে পাঠিয়ে দিন।

<AddPostEditor onAddPost={handleAddPost} />

৫.২ ডেটা আপডেট করা (PUT / PATCH)

এখন আমরা দেখব, কীভাবে ক্লায়েন্ট সাইড থেকে PUT এবং PATCH রিকুয়েস্ট দিয়ে ডেটা পরিবর্তন করতে পারি। PUT মানে- সম্পূর্ণ রো/ডকুমেন্ট পাঠিয়ে আপডেট করা, আর PATCH মানে সম্পূর্ণ রো/ডকুমেন্ট না পাঠিয়েও শুধু নির্দিষ্ট প্রোপার্টি/ফিল্ড পাঠিয়ে সম্পূর্ণ রো/ডকুমেন্টকে আপডেট করে দেওয়া যায়, এবং পুরো জিনিসটাই রেসপন্সে পাওয়া যায়।

PATCH বনাম PUT — পার্থক্যটা মনে রাখুন:

Methodকাজ
PUTপুরো object-টাই নতুন করে replace করে
PATCHশুধু যেই field(গুলো) পাঠানো হয়েছে, ওইটুকুই বদলায়

বেশিরভাগ সময় আপডেটের জন্য PATCH ব্যবহার করা হয়, কারণ পুরো পোস্ট না পাঠিয়ে শুধু পরিবর্তিত অংশটুকু পাঠানোই যথেষ্ট।

তাহলে কি PUT ছাড়াই শুধু PATCH দিয়ে অ্যাপ বানানো যায়? হ্যাঁ, পুরোপুরি যায় — এবং এটা খুবই কমন প্র্যাকটিস।

সব field পাঠালে PATCH কার্যত PUT-এর মতোই কাজ করে (পুরো resource replace হয়ে যায়)। কারণ PATCH এক টুল দিয়ে দুই কাজই (partial + full update) সামলাতে পারে, আর extra route/logic maintain করতে হয় না।

Handle Edit Post function

const handleEditPost = async (postId, updatedFields) => {
  try {
    const response = await axios.patch(
      `http://localhost:8000/posts/${postId}`,
      updatedFields,
    );

    // পুরনো posts array থেকে শুধু matching id-টা replace হবে, বাকিগুলো অপরিবর্তিত থাকবে
    setPosts((prevPosts) =>
      prevPosts.map((post) => (post.id === postId ? response.data : post)),
    );
  } catch (err) {
    setError(getFriendlyErrorMessage(err));
  }
};

যদি নিজে ইম্পলিমেন্ট করতে না পারেন। তাহলে 6.1-axios-mock-update-http-req চেকআউট করে সলুশ্যনটা দেখে নিতে পারেন।

git switch 6.1-axios-mock-update-http-req

App.jsx ফাইলে handleEditPost ফাংশনে API কল করার সময় axios.patch-এর পরিবর্তে axios.put ব্যবহার করলেও আমাদের কোড ঠিকভাবে কাজ করবে। কারণ, এখানে আমরা পোস্ট অবজেক্টের সব প্রোপার্টিই API-তে পাঠাচ্ছি। (যদিও এই উদাহরণে আইডি পাঠানো বাধ্যতামূলক নয়।)

তবে সাধারণত, কোনো রিসোর্সের নির্দিষ্ট একটি বা কয়েকটি ফিল্ড আপডেট করতে সাধারণত PATCH ব্যবহার করা হয়। আর পুরো রিসোর্সটি নতুন ডেটা দিয়ে সম্পূর্ণ প্রতিস্থাপন (replace) করতে PUT ব্যবহার করা হয়।

৫.৩ ডেটা মুছে ফেলা (Delete / DELETE)

এবার আমরা একটি পোস্ট ডিলিট করার জন্য HTTP-এর DELETE মেথড ব্যবহার করব। Axios-এ axios.delete() মেথডের মাধ্যমে খুব সহজেই কোনো রিসোর্স মুছে ফেলার জন্য API-তে রিকোয়েস্ট পাঠানো যায়।

const handleDeletePost = async (postId) => {
  const confirmed = window.confirm("পোস্টটা সত্যিই ডিলিট করতে চান?");
  if (!confirmed) return;

  try {
    await axios.delete(`http://localhost:8000/posts/${postId}`);

    // সার্ভার থেকে ডিলিট সফল হলে, সেই id বাদে বাকি সব post রাখা হচ্ছে
    setPosts((prevPosts) => prevPosts.filter((post) => post.id !== postId));
  } catch (err) {
    setError(getFriendlyErrorMessage(err));
  }
};

কোডটি ধাপে ধাপে ব্যাখ্যা করা যাক—

  • প্রথমে window.confirm() ব্যবহার করে ব্যবহারকারীর কাছ থেকে নিশ্চিত হওয়া হচ্ছে যে, তিনি সত্যিই পোস্টটি ডিলিট করতে চান কি না।
  • যদি ব্যবহারকারী Cancel চাপেন, তাহলে return স্টেটমেন্টের মাধ্যমে ফাংশনের এক্সিকিউশন সেখানেই শেষ হয়ে যায়।
  • এরপর axios.delete() ব্যবহার করে নির্দিষ্ট পোস্টের আইডিসহ API-তে একটি DELETE রিকোয়েস্ট পাঠানো হয়।
  • রিকোয়েস্ট সফল হলে filter() মেথডের সাহায্যে ডিলিট হওয়া পোস্টটি বাদ দিয়ে নতুন একটি অ্যারে তৈরি করা হয় এবং setPosts()-এর মাধ্যমে স্টেট আপডেট করা হয়।
  • আর কোনো ত্রুটি হলে catch ব্লকের মাধ্যমে ব্যবহারকারীকে একটি উপযুক্ত ত্রুটি বার্তা দেখানো হয়।

লক্ষ্য করুন, এখানে Template Literal ব্যবহার করে URL-এর শেষে নির্দিষ্ট পোস্টের id যুক্ত করা হয়েছে। PATCH এবং DELETE—উভয় ক্ষেত্রেই নির্দিষ্ট রিসোর্সে কাজ করার জন্য একই ধরনের URL প্যাটার্ন ব্যবহার করা হয়।

http://localhost:8000/posts/${postId}

যদি নিজে ইম্পলিমেন্ট করতে না পারেন। তাহলে 6.1-axios-mock-delete-http-req চেকআউট করে সলুশ্যনটা দেখে নিতে পারেন।

git switch 6.1-axios-mock-delete-http-req

৫.৪ সংক্ষিপ্ত রেফারেন্স — সব HTTP Method এক নজরে

const res = await axios.get("/posts"); // ডেটা আনা
const res = await axios.post("/posts", data); // নতুন ডেটা তৈরি
const res = await axios.put("/posts/1", data); // পুরো ডেটা replace
const res = await axios.patch("/posts/1", data); // আংশিক আপডেট
const res = await axios.delete("/posts/1"); // ডেটা মুছে ফেলা

৬. Axios Instance তৈরি করা — কোড DRY রাখা

৬.১ সমস্যা

প্রতিটা request-এ বারবার একই baseURL (http://localhost:8000) লেখা বিরক্তিকর, আর টাইপো হওয়ারও সম্ভাবনা থাকে।

৬.২ axios.create() axios instance দিয়ে সমাধান

আলাদা একটা ফাইল (api.js) ক্রিয়েট করে একবারই instance তৈরি করে ফেলুন। আর যদি নিজে নিজে ইম্প্লিমেন্ট করতে না পারেন, git switch -c 6.1-axios-mock-create-axios-instance দিয়ে চেকআউট করুন। দেখুন আমরা কিভাবে axios instance বানিয়ে নিয়েছি।

// src/api/api.js
import axios from "axios";

const api = axios.create({
  baseURL: "http://localhost:8000",
});

export default api;

৬.৩ ব্যবহার করা

import api from "./api/api";

const posts = await api.get("/posts");
// baseURL বারবার লিখতে হচ্ছে না
const newPost = await api.post("/posts", { title: "নতুন পোস্ট" });

মনে রাখুন: এখনই Authorization header যোগ করবেন না। Token dynamically যোগ করার কাজটা Interceptor দিয়ে করবো — একদম পরের সেকশনে দেখুন।


৭. Interceptors ও CORS সমস্যার সমাধান

Axios-এর সবথেকে পাওয়ারফুল ফিচার হলো Interceptors — request যাওয়ার আগে বা response আসার পরে মাঝখানে বসে কোনো কাজ করার সুযোগ।

৭.১ Request Interceptor — Header অটোমেটিক যোগ করা

প্রতিটা request পাঠানোর ঠিক আগে এটা কাজ করে। প্রতিটা call-এ আলাদা করে header এ token বসাতে হয় না:

api.interceptors.request.use((config) => {
  const token = localStorage.getItem("token");
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

৭.২ Response Interceptor — কমন Error Handling

সার্ভার থেকে response আসার পর, কিন্তু আমাদের কোডের catch ব্লকে পৌঁছানোর আগে এটা কাজ করে:

api.interceptors.response.use(
  (response) => response, // সব ঠিক থাকলে response সেভাবেই পাস হয়ে যাবে
  (error) => {
    console.error("API Error:", getFriendlyErrorMessage(error));
    return Promise.reject(error);
  },
);

এর ফলে প্রতিটা ফাংশনে আলাদা করে common error handling লজিক লিখতে হয় না— একবার interceptor-এ লিখলেই পুরো অ্যাপে কাজ করবে। পার্ট-২ তে আমরা দেখব, কিভাবে http request fail করলেও পুনরায় ২-৩ বার http request করতে পারি। এবং রিকুয়েস্টে ৪০৩ ইরোর আসলে (টোকেনের মেয়াদ) শেষ হলে, ইউজারকে না জানিয়ে রিফ্রেস টোকেন দিয়ে ভ্যালিডেড টোকেন নিয়ে এসে, আবার একটা সফল http request করতে পারি। কোডের জন্য নিচের ব্রাঞ্চে চেকআউট করুন।

git switch 6.1-axios-mock-interceptor-implement

৭.৩ CORS Error — কেন হয়

Custom header (যেমন Authorization) পাঠানোর সময় ব্রাউজার নিরাপত্তার কারণে অনেক সময় request block করে দেয়— একেই বলে CORS (Cross-Origin Resource Sharing) Error। Browser console-এ লাল অক্ষরে এই error দেখা যায়।

৭.৪ json-server-এ CORS সমাধান

json-server --watch db.json --port 8000 --no-cors

--no-cors ফ্ল্যাগ যোগ করলে json-server ব্রাউজারকে বলে দেয় cross-origin request-এ কোনো সমস্যা নেই। আসল production backend-এ CORS ঠিক করতে হয় server-side কনফিগারেশন দিয়ে — সেটা Part 2-এ দেখবো।

এই বেসিক জিনিসগুলো জানা হয়ে গেছে — Read, Create, Update, Delete, Instance, Interceptor আর CORS পর্যন্ত। এখন আসল project-এ হাত দেওয়া যাক।


আপনার জন্য একটি কাজ:

PostList.jsx-এ লক্ষ্য করুন, Edit বাটনের জন্য যেভাবে editingPostId স্টেট আর EditPostEditor কম্পোনেন্ট ব্যবহার করা হয়েছে — ঠিক একই ধাঁচে এবার একটা See More বাটন আর PostDetails কম্পোনেন্ট বানাতে হবে, যেটা ক্লিক করলে পোস্টের ডিটেইলস আলাদা করে API কল করে দেখাবে।

নির্দেশনা এবং হিন্ট:

  1. EditPostEditor-এর মতো একই স্টাইলে editingPostId-এর পাশাপাশি আরেকটি স্টেট নিন, যেমন viewingPostId, ডিফল্ট ভ্যালু null।
  2. প্রতিটি পোস্টের কার্ডে (Delete বাটনের পাশে) একটা See More বাটন বসান, যার onClick-এ setViewingPostId(post.id) কল হবে।
  3. editingPostId === post.id চেক করে যেভাবে EditPostEditor কন্ডিশনালি রেন্ডার হচ্ছে, ঠিক সেভাবেই viewingPostId === post.id চেক করে PostDetails কম্পোনেন্ট রেন্ডার করুন — অর্থাৎ card-এর ভেতরেই details দেখান, পুরো পেজ পাল্টাবেন না।
  4. নতুন PostDetails.jsx ফাইল বানান, ঠিক EditPostEditor.jsx-এর গঠন অনুসরণ করে — postId prop হিসেবে নেবে, useEffect-এ axios instance দিয়ে ওই আইডি দিয়ে আলাদা API কল করে ডেটা আনবে, আর loading/error state হ্যান্ডেল করবে।
  5. PostDetails-এ একটা Close বা Back বাটন রাখুন, যেটা ক্লিক করলে parent-এর setViewingPostId(null) কল হবে — ঠিক যেভাবে EditPostEditor-এ setEditingPostId(null) দিয়ে এডিট মোড বন্ধ করা হয়।
  6. খেয়াল রাখবেন, editingPostId আর viewingPostId — এই দুইটা স্টেট যেন একসাথে conflict না করে। চাইলে একটা বাটনে ক্লিক করলে অন্যটা রিসেট করে দিতে পারেন (যেমন See More-এ ক্লিক করলে setEditingPostId(null)ও কল করা)।

On this page

Axios দিয়ে HTTP Request হ্যান্ডেলিং — একটি সম্পূর্ণ বাংলা রিসোর্স১. Axios কী এবং কেন ব্যবহার করবো?১.১ কেন fetch-এর বদলে Axios?4xx vs 5xx http response status code২. প্র্যাকটিসের জন্য একটা ছোট্ট Backend বানিয়ে নিব — json-server২.১ json-server ইনস্টল করা২.২ db.json ফাইল বানানো২.৩ সার্ভার চালু করা২.৪ json-server - এর API Routes চেনাFrontend Ready করি:৩. প্রথম Request — Data Read করব (GET)৩.১ State সেটআপ করা৩.২ useEffect-এর ভেতরে সরাসরি async কেন লেখা যায় না?৩.৩ axios.get() দিয়ে ডেটা আনা৩.৪ UI-তে ডেটা এবং এরর দেখানো৩.৫ Response Object-এর ভেতরে কী কী থাকে?৩.৬ Request Customize করা — Config Object (Advanced)৪. Error Handling — বেসিক থেকে অ্যাডভান্স৪.১ তিন ধরনের এরর৪.২ সার্ভার এরর বনাম নেটওয়ার্ক এরর৪.৩ Dynamic Error Message বানানো৪.৪ Reusable Error Helper Function৫. ডেটা তৈরি, আপডেট ও ডিলিট করা (CRUD-এর বাকি অংশ)৫.১ নতুন ডেটা তৈরি করা (Create / POST)৫.২ ডেটা আপডেট করা (PUT / PATCH)৫.৩ ডেটা মুছে ফেলা (Delete / DELETE)৫.৪ সংক্ষিপ্ত রেফারেন্স — সব HTTP Method এক নজরে৬. Axios Instance তৈরি করা — কোড DRY রাখা৬.১ সমস্যা৬.২ axios.create() axios instance দিয়ে সমাধান৬.৩ ব্যবহার করা৭. Interceptors ও CORS সমস্যার সমাধান৭.১ Request Interceptor — Header অটোমেটিক যোগ করা৭.২ Response Interceptor — কমন Error Handling৭.৩ CORS Error — কেন হয়৭.৪ json-server-এ CORS সমাধানআপনার জন্য একটি কাজ: