এই পোস্টে, আমরা ফ্লাটার, সার্ভারলেস ফ্রেমওয়ার্ক, আপস্ট্যাশ এবং রেডিস ব্যবহার করে একটি সার্ভারলেস মোবাইল অ্যাপ্লিকেশন বিল্ড করব ডেটা স্টোরেজের জন্য।
আপস্ট্যাশ কী? 🤔
আপস্ট্যাশ হলো রেডিসের জন্য একটি সার্ভারলেস ডেটাবেস। আপস্ট্যাশের সাথে, আপনি প্রতি-রিকোয়েস্ট পে করবেন। অর্থাৎ ডেটাবেস যখন ব্যবহারে নেই তখন আপনাকে চার্জ করা হবে না।
আপস্ট্যাশ আপনার জন্য ডেটাবেস কনফিগার এবং ম্যানেজ করে। এটি ডাইনামোডিবি এবং ফায়ুনা-এর মতো অন্যান্য ডেটাবেসের একটি শক্তিশালী বিকল্প, সুবিধাগুলো সহ:
- কম লেটেন্সি
- সহজ ব্যবহার, ঠিক রেডিস এপিআই-এর মত।
এখানে একটি বিস্তারিত ডকুমেন্ট আছে আপস্ট্যাশের অন্যান্য ক্লাউড-বেসড সমাধানlerle তুলনা করে, যা আপনাকে আপনার পরবর্তী প্রজেক্টের জন্য এটি কেন বেছে নেবেন তার স্পষ্ট কারণ দেবে।
আপনি এই আর্টিকেলও চেক আউট করতে পারেন যা সব উপলব্ধ সার্ভারলেস ডেটাবেসের তুলনা করে।
আপস্ট্যাশের সাথে,
- ফ্রি থেকে শুরু করুন এবং শুধু যেটি ব্যবহার করবেন তার জন্য পে করুন
- ফাস্ট, ডিউরেবল স্টোরেজ আছে
- আপনি বিশ্বের যেকোনো কোণ থেকে আপনার ডেটাবেস অ্যাক্সেস করতে পারেন, গ্লোবাল ডেটাবেস এবং এজ ক্যাশিং-এর কারণে কম লেটেন্সিতে।
আপস্ট্যাশে আজই ফ্রিতে শুরু করুন
আপস্ট্যাশের ওপর কার্যকরভাবে অ্যাপ্লিকেশন বিল্ড করতে, আপনাকে রেডিস বুঝতে হবে। তাই রেডিসের একটি সংক্ষিপ্ত পরিচয় দিয়ে দেখি কীভাবে আমরা আমাদের আপস্ট্যাশ অ্যাপে এটি ব্যবহার করব।
যদি আপনি কিছু আরও ডিটেইলড এবং গভীর জ্ঞান পছন্দ করেন, আমি অফিসিয়াল রেডিস ওয়েবসাইট-কে রিকমেন্ড করি।
রেডিস হলো একটি ওপেন সোর্স (বিএসডি লাইসেন্সড), ইন-মেমরি ডেটা স্ট্রাকচার স্টোর, যা ডেটাবেস, ক্যাশ, এবং মেসেজ ব্রোকার হিসেবে ব্যবহৃত হয়।
এটি ব্যাপক ডেটা স্ট্রাকচার সাপোর্ট করে যেমন:
- স্ট্রিংস
- হ্যাশেস
- লিস্টস
- সেটস
- রেঞ্জ কোয়েরি সহ সোর্টেড সেটস
- বিটম্যাপস
- হাইপারলগলগস
- জিওস্পেশিয়াল ইনডেক্সেস
আপনি রেডিস ডেটাবেসের সাথে কমান্ড ব্যবহার করে ইন্টারঅ্যাক্ট করেন এবং ডেটা কি-ভ্যালু ফরম্যাটে সেভ করেন, যেখানে কি হতে পারে একটি স্ট্রিং এবং ভ্যালু হতে পারে রেডিস দ্বারা সাপোর্টেড যেকোনো ডেটা স্ট্রাকচার।
উদাহরণস্বরূপ, আমি রেডিস কমান্ড SET ব্যবহার করে আমার সারনেমের ভ্যালু সেভ করতে পারি এইভাবে:
SET surname Rosius
যেখানে surname হলো কি এবং Rosius হলো ভ্যালু।
রেডিসের সাথে একটি খুব গুরুত্বপূর্ণ বিষয় নোট করুন: সবসময় আপনার ডেটা এভাবেই স্টোর করুন যাতে আপনি সহজেই সেটি রিট্রিভ করতে পারেন।
রেডিসে ভ্যালু দিয়ে কি সার্চ করার কোনো ডায়রেক্ট উপায় নেই।
রেডিসে ডেটা পার্মানেন্টলি স্টোর হয়। তাই আমি কি surname-এ স্টোর করা ডেটা রিট্রিভ করতে পারি এইভাবে:
GET surname
রেজাল্ট: 'Rosius'
আমরা কি surname-এ স্টোর করা ভ্যালু ডিলিটও করতে পারি এইভাবে:
DEL surname
মান লেইক আমরা একটি পোস্টের লাইক্স ইনক্রিমেন্ট করতে চাই। এখানে কীভাবে আমরা সহজে এটি করতে পারি, INCR কমান্ড ব্যবহার করে, যেটি এটমিক।
SET likes 10
INCR likes => 11
INCR likes => 12
INCR likes => 13
প্রথমে, আমরা লাইক্সের ইনিশিয়াল ভ্যালু ১০ সেট করি, এবং তারপর আমরা লাইক্সের ভ্যালু এটমিকভাবে ইনক্রিমেন্ট করি। এখন, আপনি সম্ভবত চিন্তা করবেন যে likes-কে এইভাবেও ইনক্রিমেন্ট করা সম্ভব।
x = GET likes
x = x + 1
SET likes x
এটি পুরোপুরি ঠিক, যতক্ষণ আপনি আপনার অ্যাপ্লিকেশনের একমাত্র ইউজার। যা কখনোই 사실이 নয়।
যখন >২ জন একই লাইক ইনক্রিমেন্ট করবে, উপরের প্রসেস (GET, Increment, SET) আর এটমিক থাকবে না। তাই,
x = GET likes (yields 10)
y = GET likes (yields 10)
x = x + 1 (x is now 11)
y = y + 1 (y is now 11)
SET likes x (likes is now 11)
SET likes y (likes is now 11)
উপরের কোড থেকে, ইউজার ১ লাইক্সের ভ্যালু পায় যা ১০, এবং সেটি x ভেরিয়েবলে স্টোর করে, এবং একই সময় ইউজার ২ সেই একই লাইক্সের ভ্যালু পায়, যা ১০, এবং সেটি y ভেরিয়েবলে স্টোর করে।
ইউজার ১ লাইক্স(x)-এর ভ্যালুতে ১ যোগ করে এবং নতুন ভ্যালু সেট করে, যা এখন ১১।
ইউজার ২ একই কাজ করে।
তাহলে লাইক্সের ভ্যালু ১১।
কিন্তু এটা কি সত্যিই সঠিক? মনে রাখবেন লাইক্স দুবার ইনক্রিমেন্ট হয়েছে ২ জন আলাদা ইউজারের দ্বারা।
লাইক্সের ভ্যালু ১২ হওয়া উচিত ছিল, ১১ নয়। তাই রেডিস INCR কমান্ড প্রদান করে, যেটি এটমিক এবং এসব সমস্যা সমাধান করে।
হ্যাশ ডেটা টাইপ
রেডিস হ্যাশেস অন্যান্য প্রোগ্রামিং ল্যাঙ্গুয়েজের হ্যাশের সমতুল্য। মূলত, সেগুলো ফিল্ডের একটি কালেকশন যা ভ্যালুসের সাথে অ্যাসোসিয়েটেড।
উদাহরণস্বরূপ, এখানে আমি কীভাবে একটি হ্যাশে ইউজার প্রোফাইল ইনফরমেশন স্টোর করব:
HMSET userProfile:100034 "userId" 100034 "username" "Rosius Ndimofor" "firstName" "Rosius" "lastName" "Ndimofor" "profilePic" "rosius.jpeg"
প্রথমে, আমাদের হ্যাশের কি হলো userProfile:100034, তারপর আমাদের সারাদিয় key value পেয়ার। উদাহরণস্বরূপ "userId" হলো কি এবং 100034 হলো ভ্যালু। আমরা স্পেসিফিক ইউজার প্রোফাইল ইনফরমেশন যেমন ফাস্ট নেম রিট্রিভ করতে পারি HGET কমান্ড এবং userId ব্যবহার করে এইভাবে।
userId = 100034
HGET userProfile:{userId} firstName
অথবা আমরা একটি নির্দিষ্ট ইউজারের সকল ইউজার প্রোফাইল ইনফরমেশন রিট্রিভ করতে পারি HGETALL কমান্ড ব্যবহার করে এইভাবে:
userId = 100034
HGETALL userProfile:{userId}
লিস্ট ডেটা টাইপ
আগে আমি বলেছিলাম, রেডিসে, ডেটা সেভ করা খুব জরুরি সেটি যেভাবে আপনি রিট্রিভ করতে চান।
কি হবে যদি আমরা আমাদের প্ল্যাটফর্মের সব ইউজার পেতে চাই?
আমরা এখন পর্যন্ত হ্যাশ ডেটা স্ট্রাকচার ব্যবহার করেছি ইউজার প্রোফাইল ইনফরমেশন সেভ করতে। এখন আমাদের সিস্টেমের সব ইউজার পেতে হবে।
এটি সম্পন্ন করার সবচেয়ে সহজ উপায় হলো প্রতিটি ইউজারের userId'গুলো একটি লিস্টে সেভ করা LPUSH (Left Push) কমান্ড ব্যবহার করে এইভাবে:
LPUSH "users" userId
আমাদের লিস্ট থেকে সব ইউজার পেতে, আমরা LRANGE কমান্ড ব্যবহার করি এইভাবে:
LRANGE "users" 0 -1
এই কয়েকটি কমান্ড আমরা আমাদের অ্যাপ্লিকেশনে ব্যবহার করব। কিন্তু আমি আপনাকে অনুরোধ করছি রেডিস অফিসিয়াল সাইটে গিয়ে বাকি কমান্ডগুলো দেখুন এবং কীভাবে সেগুলো ব্যবহার করতে হয় সেটা শিখুন।
তাহলে আমাদের ফুল-স্ট্যাক অ্যাপ্লিকেশন কীভাবে কাজ করবে? 🤔
আপনার প্রশ্ন করার জন্য ধন্যবাদ। আজ, আমরা একটি CRUD এপিআই তৈরি করার সাথে শুরু করব। হেয়ার ইজ দিয়ুজ কেস।
আমাদের দুটি এন্টিটি আছে। Users এবং Posts।
এগুলো এক-से-অনেক রিলেশনশিপ শেয়ার করে। তাই একটি ইউজারের একাধিক পোস্ট হতে পারে, এবং একটি পোস্ট শুধু একটি ইউজারের ওনারশিপে থাকতে পারে।

একটি ইউজারকে অনুমতি:
- অ্যাকাউন্ট তৈরি করা। নো অথেনটিকেশন। আপনি AWS Cognito বা Auth0 দিয়ে অথেনটিকেশন যোগ করতে পারেন।
- তাদের অ্যাকাউন্ট আপডেট করা
- তাদের অ্যাকাউন্ট পাওয়া
- একটি পোস্ট তৈরি করা
- একটি পোস্ট আপডেট করা
- একটি পোস্ট লাইক করা
- সকল পোস্টের লিস্ট পাওয়া
এখানে সমাধানের আর্কিটেকচারাল ভিউ:
তাহলে চলুন শুরু করি।
একটি আপস্ট্যাশ অ্যাকাউন্ট তৈরি করুন
এখানে একটি ফ্রি আপস্ট্যাশ অ্যাকাউন্ট তৈরি করুন: আপস্ট্যাশ লগইন।
আপনার অ্যাকাউন্ট তৈরি হলে, একটি আপস্ট্যাশ ডেটাবেস তৈরি করুন।
ফ্রি টিয়ারে আপনাকে শুধু একটা ডেটাবেস তৈরি করার অনুমতি আছে।
আপনার রেডিস ডেটাবেস এন্ডপয়েন্ট নোট করুন। এটি কিছু এইরকম দেখাবে। rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-bee-30249.upstash.io:00049
একটি সার্ভারলেস প্রজেক্ট তৈরি করা
পূর্বশর্ত
অগ্রসর হওয়ার আগে এই ডিপেন্ডেন্সিগুলো ইনস্টল করুন:
AWS CLI
NodeJS
Serverless CLI
নিচের কমান্ড ব্যবহার করে একটি নতুন সার্ভারলেস প্রজেক্ট তৈরি করুন এবং প্রম্প্ট ফলো করুন।
serverless

Node.js HTTP API সিলেক্ট করুন, আপনার প্রজেক্টকে একটি নাম দিন, এবং enter চাপুন।
আমার সার্ভারলেস প্রজেক্টের ইনিশিয়াল স্ট্রাকচার:

সেই ফোল্ডারের ভেতরে npm init কমান্ড দিয়ে একটি নতুন নোড প্রজেক্ট আরম্ভ করুন।
এরপর, রেডিস ক্লায়েন্ট ইনস্টল করুন:
npm install ioredis
একটি ইউনিভার্সালি ইউনিক আইডেন্টিফায়ার (uuid) ডিপেন্ডেন্সিও ইনস্টল করুন। আমরা এটি এই প্রজেক্টে ব্যাপকভাবে ব্যবহার করব।
npm install uuid
এখন, আপনার রেডিস ডেটাবেস এন্ডপয়েন্টকে serverless.yml ফাইলে এনভায়রনমেন্ট ভেরিয়েবল হিসেবে যোগ করুন এইভাবে।
provider:
name: aws
region: us-east-1
stage: dev
runtime: nodejs12.x
lambdaHashingVersion: "20201221"
environment:
REDIS_CLIENT: "rediss://:2c9bb162c2444bf7ab689640bb2ead23@gusc1-smashing-wasp-30249.upstash.io:30249"
এরপর, আপনার প্রজেক্টের ভেতরে users এবং posts নামে দুটি ফোল্ডার তৈরি করুন। এই দুটি ফোল্ডার তাদের রেসপেক্টিভ ইউজ কেসের জন্য ল্যাম্বডা ফাংশন ধারণ করবে।

চলুন আমাদের এপিআই এন্ডপয়েন্টগুলো তৈরি করা শুরু করি।
ইউজার তৈরি করুন
আমরা চাই ইউজাররা তাদের জন্য অ্যাকাউন্ট তৈরি করতে পারে।
নো অথেনটিকেশন। তাদের শুধু জমা দিতে হবে:
- ইউজারনেম
- ফাস্ট নেম
- লাস্ট নেম
- প্রোফাইল পিকচার
user ফোল্ডারে create.js নামে একটি ফাইল তৈরি করুন।
ফাইলের শীর্ষে, রেডিস ক্লায়েন্ট ইমপোর্ট এবং ইনস্ট্যানশিয়েট করুন serverless.yml ফাইলে সেভ করা রেডিস ডেটাবেস ইউআরএল ব্যবহার করে এনভায়রনমেন্ট ভেরিয়েবল হিসেবে।
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
আমরা uuid ডিপেন্ডেন্সি ও ইমপোর্ট করি, কারণ আমরা এটি ব্যবহার করব ইউজারদের জন্য ইউনিক আইডি তৈরি করতে।
প্রথমে, আমাদের একটি ডেটা স্ট্রাকচার দরকার user profile ইনফরমেশন সেভ করতে, এবং অন্যটি সকল ইউজারের userId সেভ করতে অ্যাপ্লিকেশনে।
হ্যাশ এবং লিস্ট ডেটা টাইপ মনে আছে?
হ্যাশ ডেটা টাইপ ইউজার প্রোফাইল ইনফরমেশন সেভ করতে। ডেটা টাইপ কি userItem:${userId} নোট করুন।
await client.hmset(
`userItem:${userId}`,
"userId", userId,
"username", data.username,
"firstName", data.firstName,
"lastName", data.lastName,
"profilePic", data.profilePic,
"timestamp", timestamp
);
তারপর আমরা তৈরি হওয়া userId কে users নামক একটি লিস্টে সেভ করি।
await client.lpush("users", userId);
আপনি লক্ষ্য করেছেন, আমাদের ২টি অপারেশন পাঠাতে হচ্ছে। সেগুলো একে পর এক পাঠানো সম্ভব, কিন্তু সেটা অপ্টিমাল নয়।
আপস্ট্যাশ ব্যাচ অপারেশন সাপোর্ট করে, একটি ফিচার যাকে pipelining বলা হয়।
তাই সিঙ্গল কমান্ড পাঠিয়ে রেসপন্সের জন্য অপেক্ষা করার বদলে, আমরা একসাথে একাধিক কমান্ড পাঠাতে পারি এবং রেসপন্সও একই রকম পাবো।
পাইপলাইনিং ব্যবহার করে আমাদের অপারেশন কেমন দেখাবে:
client.pipeline(
await client.hmset(
`userItem:${userId}`,
"userId", userId,
"username", data.username,
"firstName", data.firstName,
"lastName", data.lastName,
"profilePic", data.profilePic,
"timestamp", timestamp
),
await client.lpush("users", userId)
);
তারপর আমরা সেভ করা ইউজার প্রোফাইল ইনফো পেয়ে সেটি রেসপন্স হিসেবে রিটার্ন করতে পারি api-gateway দিয়ে।
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);

serverless.yml আপডেট করা न भুলে এই এন্ডপয়েন্ট রিফ্লেক্ট করতে।
functions:
createUser:
handler: user/create.createUser
events:
- http:
path: /user
method: post
আমাদের ফাংশনের নাম createUser, এবং এটি অবস্থিত create.js নামে একটি ফাইলে যা user নামে একটি ফোল্ডারের ভেতরে। তাই হ্যান্ডলার user/create.createUser।
পাথ /user নোট করুন।
createUser ফাংশন post এইচটিটিপি মেথড ব্যবহার করে।
users/create.js ফাইলের সম্পূর্ণ কোড:
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";
const profilePic = "profilePic";
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
* @param {username,firstName,lastName,profilePic} event
* @returns
*/
module.exports.createUser = async (event) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
if (data == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't create the user item",
}, null, 2),
};
}
const userId = uuid.v1();
console.log(`userId is ${userId}`);
// here, we use a pipeline to perform multiple requests
// Firstly, we save the user details to a hash dataset with key (`userItem:${userId}`)
client.pipeline(
await client.hmset(
`userItem:${userId}`,
"userId", userId,
"username", data.username,
"firstName", data.firstName,
"lastName", data.lastName,
"profilePic", data.profilePic,
"timestamp", timestamp
),
await client.lpush("users", userId)
);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
ইউজার আপডেট করুন
ইউজাররা সময়-सময়ে তাদের প্রোফাইল আপডেট করতে চান। তাই একটি ইউজার আপডেট এন্ডপয়েন্ট দেয়া যাক।
এই অপারেশনের জন্য একমাত্র কমান্ড যা দরকার সেটি হলো HMSET কমান্ড এবং userId।
রেডিস ডকুমেন্টেশন থেকে, এখানে একদম সঠিকভাবে HMSET কমান্ড কীভাবে কাজ করে সেটি দেখানো হয়েছে।
হ্যাশে নির্দিষ্ট ফিল্ডগুলো তাদের রেসপেক্টিভ ভ্যালুতে সেট করে যেটি কি-তে স্টোর করা আছে। এই কমান্ড হ্যাশে ইতিমধ্যে বিদ্যমান নির্দিষ্ট ফিল্ডগুলোকে ওভাররাইট করে।
কোডটি কেমন দেখে:
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
const username = "username";
const firstName = "firstName";
const lastName = "lastName";
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
* @param {username,firstName,lastName,age,profilePic} event
* @returns
*/
module.exports.updateUser = async (event) => {
const timestamp = new Date().getTime();
const userId = event.pathParameters.id;
const data = JSON.parse(event.body);
if (userId == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't update the user item",
}, null, 2),
};
}
//get
await client.hmset(
`userItem:${userId}`,
"username", data.username,
"firstName", data.firstName,
"lastName", data.lastName
);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
তারপর, serverless.yml ফাইলে, ফাংশনস এর অধীনে যোগ করুন...
updateUser:
handler: user/update.updateUser
events:
- http:
path: /user/{id}
method: put
আমরা userId পাস করছি পাথ প্যারামিটার হিসেবে /user/{id}।

ইউজার পান
HGETALL কমান্ড এবং হ্যাশ কি ব্যবহার করে, আমরা একটি নির্দিষ্ট ইউজারের জন্য ইউজার প্রোফাইল ইনফরমেশন পেতে পারি।
মনে রাখবেন যে আমরা HGET কমান্ডও ব্যবহার করতে পারি ইউজার স্পেসিফিক ইনফরমেশন পেতে যেমন firstName বা lastName ইত্যাদি।
কোডটি দেখি:
user ফোল্ডারে get.js নামে একটি ফাইল তৈরি করুন।
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getUserById = async (event) => {
const userId = event.pathParameters.id;
if (userId == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't get the user item",
}, null, 2),
};
}
console.log(`userId is ${userId}`);
//get and display saved user item
const userItem = await client.hgetall(`userItem:${userId}`);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(userItem),
};
};
তারপর serverless.yml ফাইলে,
getUser:
handler: user/get.getUserById
events:
- http:
path: /user/{id}
method: get

ইউজার লিস্ট করুন
যখন আমরা ইউজার তৈরি করার হ্যান্ডলার লিখেছিলাম, মনে আছে আমরা লेफট পুশ (LPUSH) করেছিলাম userId'গুলো users লিস্টে।
এখন, আমাদের সকল আইডি গ্র্যাব করতে হবে LRANGE কমান্ড ব্যবহার করে।
নোট: LRANGE খুব ইফিশিয়েন্ট নয় যদি পোস্টের লিস্ট খুব বড় হয়ে যায়, এবং আমরা লিস্টের মাঝপথে অবস্থিত এলিমেন্টগুলো অ্যাক্সেস করতে চাই, যেহেতু রেডিস লিস্ট লিংকড লিস্ট দ্বারা ব্যাকড। যদি কোনো সিস্টেম মিলিয়ন আইটেমের ডিপ পেজিনেশন জন্য ডিজাইন করা হয়, তবে সোর্টেড সেটস ব্যবহার করা ভালো।
সব userId পাওয়ার পর, আমরা প্রতিটি id এর মাধ্যমে লুপ করে ইউজার প্রোফাইল ইনফরমেশন পেতে পারি HGETALL ব্যবহার করে।
কোডে কেমন দেখে:
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getAllUsers = async (event) => {
let users = [];
let response = await client.lrange("users", 0, -1);
async function getAllUsers() {
let users = [];
await Promise.all(
response.map(async (userId) => {
const item = await client.hgetall(`userItem:${userId}`);
users.push(item);
console.log(users);
})
);
return users;
}
users = await getAllUsers();
return {
statusCode: 200,
body: JSON.stringify(users),
};
};
serverless.yml এর জন্য:
listUsers:
handler: user/list.getAllUsers
events:
- http:
path: /users
method: get

এবং এইভাবে users এন্ডপয়েন্টগুলো শেষ। আপনি অগো যেতে পারেন এবং আপনার অ্যাপ ডিপ্লয় করতে পারেন, যদি ইতিমধ্যে না করে থাকেন।
sls deploy
পোস্ট
একটি ইউজার অ্যাকাউন্ট তৈরি করার পর, তাদের অনুমতি দিতে হবে:
- একটি পোস্ট তৈরি করা
- আইডি দিয়ে পোস্ট পাওয়া
- তাদের পোস্টের লিস্ট পাওয়া
- একটি পোস্ট লাইক বা আনলাইক করা (পোস্টে রিয়াক্ট করা)
চলুন শুরু করি।
একটি পোস্ট তৈরি করুন
একটি পোস্ট তৈরি করার জন্য প্রয়োজনীয় প্যারামিটারগুলো:
- userId
- postId (UUID দ্বারা অটো-জেনারেটেড)
- postText
- postImage
- createdOn
৩টি ধাপ জড়িত।
HMSETকমান্ড ব্যবহার করে পোস্ট ডিটেইলস একটি হ্যাশ কি-তে সেট করুনpostItem:${postId}।LPUSHকমান্ড ব্যবহার করে postIdpostsলিস্টে যোগ করুন।LPUSHকমান্ড ব্যবহার করে postIduserPost:${userId}লিস্টে যোগ করুন।
এই টাস্ক ক্রোনোলজিক্যালি এক্সিকিউট করতে আমরা পাইপলাইন ব্যবহার করব।
post ফোল্ডারে create.js নামে একটি ফাইল তৈরি করুন এবং নিচের কোড যোগ করুন।
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
* @param {userId,postId,postText,postImage,createdOn} event
* @returns
*/
module.exports.createPost = async (event) => {
const timestamp = new Date().getTime();
const postId = uuid.v1();
const data = JSON.parse(event.body);
if (data == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't create the Post item",
}, null, 2),
};
}
console.log(`postId is ${postId}`);
client.pipeline(
await client.hmset(
`postItem:${postId}`,
"id", postId,
"userId", data.userId,
"postText", data.postText,
"postImage", data.postImage,
"createdOn", timestamp
),
await client.lpush("posts", postId),
await client.lpush(`userPost:${data.userId}`, postId)
);
//get and display saved post item
const postItem = await client.hgetall(`postItem:${postId}`);
console.log(postItem);
return {
statusCode: 200,
body: JSON.stringify(postItem),
};
};
তারপর, serverless.yml-এ ফাংশনস এর অধীনে যোগ করুন:
createPost:
handler: post/create.createPost
events:
- http:
path: /post
method: post
ডিপ্লয় এবং টেস্ট করুন।

আইডি দিয়ে পোস্ট পান
আইডি দিয়ে পোস্ট পাওয়ার সময়, আমরা পোস্টের ডিটেইলস পাওয়ার পাশাপাশি পোস্ট অ্যাডমিনের ডিটেইলস এবং পোস্টটির এতক্ষণে কতগুলো রিয়াকশন (লাইক) পেয়েছে সেটিও আটাচ করতে চাই।
আমি জানি আমরা এখনো পোস্ট লাইক বা আনলাইক নিয়ে দেখিনি, শুধু ধৈর্য ধরুন, সেটাও আসছে। post ফোল্ডারে get.js নামে একটি ফাইল তৈরি করুন এবং এটি সেভ করুন।
"use strict";
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
module.exports.getPostById = async (event) => {
const postId = event.pathParameters.id;
if (postId == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't get the post item",
}, null, 2),
};
}
console.log(`postId is ${postId}`);
//get and display saved post item
const postItem = await client.hgetall(`postItem:${postId}`);
const userItem = await client.hgetall(`userItem:${postItem.userId}`);
const postReactionsCount = await client.get(`postReactionsCount:${postId}`);
postItem["postAdmin"] = userItem;
postItem["reactionCount"] = postReactionsCount == null ? 0 : postReactionsCount;
console.log(postItem);
console.log(userItem);
return {
statusCode: 200,
body: JSON.stringify(postItem),
};
};
উপরের কোড থেকে, প্রথমে, আমরা একটি নির্দিষ্ট পোস্টের সকল ডিটেইলস পাই hgetall কমান্ড এবং কি postItem:${postId} ব্যবহার করে।
তারপর, যেহেতু পোস্ট অবজেক্টে পোস্ট তৈরিকারী ইউজারের userId আছে (পোস্ট অ্যাডমিন), আমরা userItem:${postItem.userId} ব্যবহার করে সেই ইউজারের ডিটেইলস পাই।
মনে রাখবেন এটি সেম কি যা আমরা উপরের ক্রিয়েট ইউজার এন্ডপয়েন্টে ব্যবহার করেছিলাম।
তৃতীয়, আমরা পোস্ট রিয়াকশন কাউন্ট পাই get কমান্ড এবং একটি কি postReactionsCount:${postId} ব্যবহার করে যা আমরা পরে পোস্ট রিয়াকশন কাউন্ট সেভ করতে ব্যবহার করব।
ডিপ্লয় এবং টেস্ট করুন।

একটি পোস্টে রিয়াক্ট করুন
এটি পুরো অ্যাপ্লিকেশনের সবচেয়ে ইন্টারেস্টিং এন্ডপয়েন্ট। লিখতে খুব মজা লাগলো।
এক ইউজারকে অনুমতি দেওয়া হয় পোস্ট লাইক বা আনলাইক করার। এখন, যখন একজন ইউজার লাইক বাটনে ক্লিক করে, আমরা প্রথমে চেক করি এই ইউজার আগে কি পোস্টটি লাইক করেছিল।
যদি হ্যাঁ, তবে আমরা পোস্টটি আনলাইক করি। নয়ত, আমরা পোস্টটি লাইক করি।
বুঝতে পেরেছেন?
ইনস্টাগ্রাম বা টুইটারের মত।
post ফোল্ডারে react_to_post.js নামে একটি ফাইল তৈরি করুন।
এন্ডপয়েন্টটি userId এবং postId নেয় পাথ প্যারামিটার হিসেবে।
একটি নতুন কমান্ড দেখি। সোর্টেড সেট। আমরা একটি সোর্টেড সেট ব্যবহার করব পোস্ট লাইক করা ইউজারের userId এবং সেটি লাইক করা টাইমস্ট্যাম্প যোগ করতে।
zadd(`postReactions:${postId}`, timestamp, data.userId)
কিটি হলো postReactions:${postId}।
সোর্টেড সেট Z দিয়ে শুরু হয়। রেডিস ডকুমেন্টেশন থেকে, zadd:
নির্দিষ্ট সকোর সহ নির্দিষ্ট মেম্বারগুলো সোর্টেড সেটে যোগ করে যেটি কি-তে স্টোর করা আছে। একাধিক স্কোর/মেম্বার পেয়ার স্পেসিফাই করা সম্ভব। যদি একটি স্পেসিফাইড মেম্বার ইতিমধ্যে সোর্টেড সেটের মেম্বার হয়, তবে স্কোর আপডেট হয় এবং এলিমেন্টটি সঠিক অর্ডার মেইনটেইন করার জন্য সঠিক পজিশনে রিইনসার্ট হয়।
পরবর্তী ধাপ হলো postReactionsCount:${postId} কে incr` কমান্ড দিয়ে ইনক্রিমেন্ট করা।
মনে রাখবেন আমরা উপরের কিটি ব্যবহার করেছিলাম গেট পোস্ট বাই আইডি এন্ডপয়েন্টে পোস্ট-রিয়াকশন কাউন্ট পেতে।
incr(`postReactionsCount:${postId}`),
শেষে, আমরা ইউজার পোস্ট রিয়াকশন ডিটেইলস একটি হ্যাশে সেভ করি।
hmset(`userPostReactions:${data.userId}`,
"postId", postId,
"userId", data.userId,
"timestamp", timestamp
),
এই সব বেসড ওন, এখানে যেই এক্সেস প্যাটার্নগুলো উপলব্ধ:
- পোস্ট রিয়াকশন কাউন্ট পাওয়া যায়।
- এক পোস্টে রিয়াক্ট করা সকল ইউজার পাওয়া যায়, অ্যাসেন্ডিং বা ডেসেন্ডিং অর্ডারে।
- এক ইউজার যে সকল পোস্টে রিয়াক্ট করেছে সেগুলো পাওয়া যায়।
আগে আমরা বলেছিলাম, আমাদের একটি চেক করতে হবে দেখতে ইউজার আগে কি পোস্টটি লাইক করেছিল। যদি হ্যাঁ, তবে সেই পোস্ট আনলাইক করব। নয়ত লাইক করব।
আমরা zscore কমান্ড ব্যবহার করব এই জন্য।
সোর্টেড সেটে কি-তে মেম্বারের স্কোর রিটার্ন করে। যদি মেম্বার সোর্টেড সেটে না থাকে, অথবা কি অস্তিত্বে না থাকে, তবে nil রিটার্ন করা হয়।
zscore(`postReactions:${postId}`, data.userId);
যদি zscore null হয়, তবে ইউজার লাইক করেনি। অন্যথায়, ইউজার লাইক کرده।
সম্পূর্ণ কোড কেমন দেখে:
"use strict";
const uuid = require("uuid");
var Redis = require("ioredis");
if (typeof client === "undefined") {
var client = new Redis(process.env.REDIS_CLIENT);
}
/**
* @param {userId,postId,postText,postImage,createdOn} event
* @returns
*/
module.exports.reactToPost = async (event) => {
const timestamp = new Date().getTime();
const data = JSON.parse(event.body);
const postId = event.pathParameters.id;
if (data == null || postId == null) {
return {
statusCode: 400,
body: JSON.stringify({
message: "Couldn't react to the Post",
}, null, 2),
};
}
console.log(`postId is ${postId}`);
console.log(`userId is ${data.userId}`);
// first check if user has already liked the post
const hasUserReacted = await client.zscore(
`postReactions:${postId}`,
data.userId
);
if (hasUserReacted == null) {
//user hasn't reacted.
client.pipeline(
await client.incr(`postReactionsCount:${postId}`),
await client.zadd(`postReactions:${postId}`, timestamp, data.userId),
await client.hmset(
`userPostReactions:${data.userId}`,
"postId", postId,
"userId", data.userId,
"timestamp", timestamp
)
);
} else {
//user already reacted, so unreact
client.pipeline(
await client.decr(`postReactionsCount:${postId}`),
await client.zrem(`postReactions:${postId}`, data.userId),
await client.hdel(
`userPostReactions:${data.userId}`,
"postId", postId,
"userId", data.userId,
"timestamp", timestamp
)
);
}
//return the post reaction count
const postReactionsCount = await client.get(`postReactionsCount:${postId}`);
console.log(postReactionsCount);
return {
statusCode: 200,
body: JSON.stringify({
postReactionCount: parseInt(postReactionsCount),
}),
};
};
serverless.yml-এ:
reactToPosts:
handler: post/react_to_post.reactToPost
events:
- http:
path: /post/{id}/react
method: post
ডিপ্লয় এবং টেস্ট করুন।

আপনার এপিআই টেস্টারের (আমি পোস্টম্যান ব্যবহার করি) সেন্ড বাটনে একাধিকবার হিট করুন এবং দেখুন কীভাবে "postReactionCount" ০ এবং ১ এর মাঝে টগল করছে।
UserId চেঞ্জ করে আবার চেক করুন।
এই এপিআই-তে আরও অনেক এক্সেস প্যাটার্ন এবং ফিক্স যোগ করা যেতে পারে।
চ্যালেঞ্জ নিন এটাকে এক্সপ্যান্ড করতে এবং আরও শিখতে।
সম্পূর্ণ সোর্স কোড-র লিংক।
রেডিসের그렇게 ঢালো না হওয়া লার্নিং কার্ভ এবং এই ফ্যাক্ট যে এটি আমাকে ডেটা সেভ করতে দেয় সেভ ভাবে যেভাবে আমি রিট্রিভ করব, সেটি আমি খুব পছন্দ করি।
অ্যাপ ডেভেলপমেন্ট শুরু করার আগে সবসময় আপনার এক্সেস প্যাটার্ন জানুন।
এই পিস লিখতে আমার খুব মজা লাগলো, আশা করি আপনি একদুই কichu শিখেছেন।
কहीं ভুল করলাম? আপনার মত একটি সুপার সায়ান কখনো হিচকিচাবে না আমাকে জানাতে।
পরবর্তী আর্টিকেলে, আমরা এই এপিআই কনসিউম করার জন্য একটি ফ্লাটার অ্যাপ বিল্ড করব। 기다রুন।
হ্যাপি কোডিং কমরেড✌🏿
রেফারেন্স
- আপস্ট্যাশ ডকস
- রেডিস
- ফ্লাটার
- ইন্টারনেট থেকে ডেটা ফেচ করা