Next JSRoutingRoute Handlers

route.js for backend

nextjs একটি full-stack framework. এটা দিয়ে backend & frontend সবকিছুই বানানো সম্ভব। আর এই backend REST API বানানোর জন্য route.js/route.ts file ব্যবহার হয়ে থাকে।

🔗 Reference

Supported HTTP Methods

GET, POST, PUT, PATCH, DELETE, HEAD, and OPTIONS. যদি unsupported কোন method call করা হয়, তাহলে Next.js 405 Method Not Allowed response পাঠাবে।

🔗 Reference

GET Request

GET request এর response এ return new Response() এভাবে return করা যাবে, এক্ষেত্রে অবশ্যই new Response(data) return করতে হবে।

app/api/blogs/route.js
// dependencies
import { blogs } from "@/data/blogs";
 
// get all blogs
export const GET = async () => {
  return new Response(JSON.stringify(blogs));
};

অথবা json() respone send করা যাবে। এক্ষেত্রে শুধুমাত্র Response.json(data) return করতে হবে।

app/api/blogs/route.js
// dependencies
import { blogs } from "@/data/blogs";
 
// get all blogs
export const GET = async () => {
  return Response.json(blogs);
};

GET Request Single Data

singe data get করার জন্য parameter এর help নিতে হবে। আর dynamic route বানাতে হবে আগের নিয়মেই। GET request এর মধ্যে 1st parameter “request” , 2nd parameter “params” object পাওয়া যায়। যেটার params object এর মধ্যে এভাবে পাওয়া যাবে এখন params এ পাওয়া id কে destructure করে parseInt(params.id) করে ডেটাবেসে find করে json response send করতে হবে। parseInt করার কারণ হচ্ছে url parameter এ পাওয়া dynamic id string format এর হয়ে থাকে। আর এখানে id param আসার কারণ হচ্ছে route এর dynamic folder [id] এভাবে নেওয়া হয়েছে।

app/api/blogs/[id]/route.js
// dependencies
import { blogs } from "@/data/blogs";
 
// get single blog
export const GET = async (req, { params }) => {
  // getting blog id from parameter
  const { id } = params;
 
  // get blog
  const blog = blogs.find((blog) => blog.id === parseInt(id));
 
  // if blog not found
  if (!blog) {
    return new Response(
      JSON.stringify({ message: `Blog not found with blog id ${id}!` }),
      {
        status: 404,
      }
    );
  }
 
  // send response
  return Response.json(blog);
};

POST Request

নতুন ডেটা যদি ডেটাবেসে সেভ করতে চাই, তাহলে POST method ব্যবহার করতে হবে। সব controller async function বানানো উচিত। POST method এর first parameter এ request পাওয়া যায়। আমরা যেহেতু json type data send করেছি তাই request.json() এর মাধ্যমে data receive করতে পারবো। নিচের উদাহরণে যেহেতু database হিসেবে একটা array of object use করেছি, তাই সেই array এর মধ্যে push করে new created data return করা হয়েছে। Response.json(data, {options}) এখানে 2nd arguments এর মধ্যে status, headers etc send করা যায়।

app/api/blogs/route.js
// create blog
export const POST = async (request) => {
  // getting payload
  const data = await request.json();
 
  // calculate nextId
  const nextId = blogs[blogs?.length - 1].id + 1;
 
  // new blog
  const newBlog = { id: nextId, ...data };
 
  // add new blog in db
  blogs.push(newBlog);
 
  return new Response(JSON.stringify(newBlog), {
    headers: {
      "Content-Type": "application/json",
    },
    status: 201,
  });
};

DELETE Request

কোন single data delete করার জন্য params এর মধ্যে id দিয়ে DELETE Request send করতে হবে। নিচে একটি array of object থেকে data delete করে দেখানো হয়েছে। আসলে এই Delete এর ব্যাপারটা vary করে data কি database নাকি কোন array of object থেকে delete করা হচ্ছে, কেননা ভিন্ন data source এর জন্য ভিন্ন system এ data delete handle করা হবে।

app/api/blogs/[id]/route.js
// delete single blog
export const DELETE = async (_req, { params }) => {
  // get id
  const { id } = params;
 
  // deletable blog index
  const editableBlogIndex = blogs.findIndex((blog) => blog.id === parseInt(id));
 
  //   remove blog
  blogs.splice(editableBlogIndex, 1);
 
  return Response.json(blogs);
};

PATCHPUT Request

কোন Data partially update করার জন্য PATCH method আর fully update করার জন্য PUT method ব্যবহার করা হয়ে থাকে। এই দুই ধরনের request এর জন্য একই ধরনের controller দিয়েই কাজ হয়ে যায়।

app/api/blogs/[id]/route.js
// edit single blog
export const PATCH = async (req, { params }) => {
  // getting data
  const data = await req.json();
  const { id } = params;
 
  // editable blog index
  const editableBlogIndex = blogs.findIndex((blog) => blog.id === parseInt(id));
 
  blogs[editableBlogIndex] = { ...blogs[editableBlogIndex], ...data };
 
  return Response.json(blogs);
};

Redirection

API route এর মধ্যেই প্রয়োজনে redirect করানো সম্ভব। নিচের উদাহরণে single blog যদি database এ না পাওয়া যায়, তখন blogs segment এ redirect করা হচ্ছে। ফলে, blogs segment এ get request এ যে response পাওয়া যেত সেটা return করবে।

app/api/blogs/[id]/route.js
// dependencies
import { blogs } from "@/data/blogs";
import { redirect } from "next/navigation";
 
// get single blog
export const GET = async (req, { params }) => {
  // getting blog id from parameter
  const { id } = params;
 
  // get blog
  const blog = blogs.find((blog) => blog.id === parseInt(id));
 
  // redirect to all blogs if blog not found
  if (!blog) {
    redirect("/api/blogs");
  }
 
  // send response
  return Response.json(blog);
};

Headers

Get Request headers

প্রতিটা HTTP Request & Response এর সাথেই headers pass হয়ে থাকে। আমরা আমাদের প্রয়োজনে Request ও Response উভয় header set & read করতে পারি। Request headers set করা হয় যে client থেকে request করা হয় সেখান থেকে। আর Response headers set করা হয় server থেকে।

নিচে Request headers read করার পদ্ধতি দেখানো হয়েছে। Request headers read করার জন্য next/headers থেকে headers নামে একটি function পাওয়া যায়। এই function invoke করলেই headersList পাওয়া যাবে, যদি sepecific কোন header পেতে চাই তাহলে headers() invoke করে সেটার উপরে get() দিলেই পাওয়া যাবে। নিচে Authorization get করে দেখানো হয়েছে।

app/api/profile/route.js
import { headers } from "next/headers";
 
export const GET = async () => {
  const headerList = headers();
 
  console.log(headerList.get("Authorization"));
 
  return Response.json("Profile route!");
};

Set Response headers

নিচে Response headers এর মধ্যে Content-Type set করে দেওয়া হয়েছে। আর Response এর মধ্যে কিছু add করতে চাইলে Response এর instance create করে কাজ করতে হবে, যেটা নিচে follow করা হয়েছে।

export const GET = async () => {
 
  return new Response(JSON.stringify({...}), {
    headers: {
      "Content-Type": "application/json"
    }
  });
};

Cookies

Client এর Cookies set এবং get করার জন্য next/headers এর মধ্যে cookies() নামে একটি function পাওয়া যায়।

Set cookies

নিচে theme নামে একটি cookie set করা হয়েছে, যেটার ভেলু dark রাখা হয়েছে। cookie set করার জন্য next/headers থেকে cookies named import করতে হবে। এই function এর set() method দিয়ে key & value pair হিসেবে cookie সেট করতে হবে।

import { cookies } from "next/headers";
 
export const GET = async () => {
  // set cookies
  cookies().set("theme", "dark");
 
  return Response.json("Profile route!");
};

Get cookies

cookie get করার জন্য cookies() থেকে get() method এর মধ্যে cookie set করার সময় যে key দেওয়া হয়েছিল সেটা দিলেই ঐ cookie পাওয়া যাবে।

import { cookies } from "next/headers";
 
export const GET = async () => {
  // get theme from cookie
  console.log(cookies().get("theme"));
 
  return Response.json("Profile route!");
};

Caching

nextjs by default সকল static GET method কে cache করা রাখে।

কখন কখন cache হয় না?

  • export const dynamic = "force-static" এটি যখন কোন route.js এর একদম উপরে রাখা হবে।
  • কোন dynamic segment এর মধ্যেকার GET method কে cache করে না। যেমনঃ api/blog/[id]/route.js এই ফাইলের মধ্যে যে GET method থাকবে সেটা cache হবে না।
  • যদি GET method এর মধ্যে কোন dynamic function থাকে। যেমনঃ headers(), cookies()
  • GET method ছাড়া বাকি সব method কোনটাই cache হবে না।

GET method এর মধ্যে কিভাবে cache বন্ধ করা যায়?

যে route এর GET method কে cache করতে না চাই, সেটার উপরে ১ম লাইনের ঐ কোড দিয়ে দিতে হবে। আর যেভাবে আছে সেভাবেই দিতে হবে।

export const dynamic = "force-static";
 
export const GET = async () => {
  return Response.json("Profile route!");
};