এই টিউটোরিয়াল সিরিজের পার্ট ২-এ স্বাগতম। প্রথম পার্টে, আমরা দেখেছি কীভাবে আপস্ট্যাশ, সার্ভারলেস ফ্রেমওয়ার্ক এবং রেডিস ব্যবহার করে একটি রেস্ট এপিআই বিল্ড করতে হয়।
এই পার্টে, আমরা ফ্লাটার ব্যবহার করে একটি মোবাইল অ্যাপ্লিকেশন বিল্ড করব, যেটি আমাদের রেস্ট এপিআই এন্ডপয়েন্টগুলো কনসিউম করবে।
চলুন শুরু করি 🙃
প্রথমে, আপনার কম্পিউটারে ফ্লাটার ইনস্টল এবং রানিং থাকতে হবে।
- ফ্লাটার
আপনার আইডিতে একটি নতুন ফ্লাটার প্রজেক্ট তৈরি করুন এবং আপনার পছন্দের নাম দিন।
আপনার ফ্লাটার প্রজেক্টের রুট ডিরেক্টরিতে pubspec.yaml ফাইল খুলুন এবং dev_dependencies এর অধীনে এই ডিপেন্ডেন্সিগুলো যোগ করুন:
timeago: ^3.1.0
shared_preferences: ^2.0.6
http: ^0.13.4
তাহলে ফাইনালি এটা এমন দেখাবে:
dev_dependencies:
flutter_test:
sdk: flutter
timeago: ^3.1.0
shared_preferences: ^2.0.6
http: ^0.13.4
timeago লাইব্রেরি ইউনিক্স টাইমস্ট্যাম্প (১৬৩৬৮২৪৮৪৩) কে মানব-পঠনীয় ফরম্যাটে কনভার্ট করে যেমন এক মিনিট আগে, ৫ মিনিট আগে ইত্যাদি।
একবার ইউজার অ্যাকাউন্ট তৈরি হলে, আমরা তাদের userId এবং অন্যান্য মাইনর ডিটেইলস ট্র্যাক রাখতে চাই। সেজন্য আমরা shared_preferences ব্যবহার করব। তারপর http` লাইব্রেরি ব্যবহার করব HTTP কল করার জন্য।
চলুন শুরু করি...
ইউজার তৈরি করুন
আমরা যে প্রথম স্ক্রিন বিল্ড করব সেটি হলো ক্রিয়েট ইউজার স্ক্রিন, যেটি ক্রিয়েট ইউজার এন্ডপয়েন্ট কনসিউম করবে।
স্ক্রিনটি কেমন দেখাবে:
বান্নির ছবি নিয়ে চিন্তা করবেন না। শুধু ইমেজভিউর প্লেসহোল্ডার।
lib ফোল্ডারের ভেতরে account নামে একটি ফোল্ডার তৈরি করুন এবং তারপর account ফোল্ডারের ভেতরে create_profile_screen.dart নামে একটি নতুন ফাইল তৈরি করুন।
আমার ফাইনাল lib ফোল্ডার স্ট্রাকচার কেমন দেখে:
একটি নতুন ইউজার তৈরি করতে আমাদের দরকার:
- প্রোফাইল পিক ইউআরএল
- ফাস্ট نیم
- লাস্ট نیم
- ইউজারনেম
- এন্ডপয়েন্ট
কোডটি দেখি:
static const String CREATE_USER_PROFILE_URL = "https://5vafvrk8kj.execute-api.us-east-1.amazonaws.com/dev/user";
bool _loading = false;
Future createUserProfile() async {
setState(() {
_loading = true;
});
print(usernameController.text);
print(firstNameController.text);
print(lastNameController.text);
print(profilePicUrl);
await http.post(Uri.parse(CREATE_USER_PROFILE_URL),
body: convert.jsonEncode({
'username': usernameController.text,
"firstName": firstNameController.text,
"lastName": lastNameController.text,
"profilePic": profilePicUrl
})).then((response) async {
var jsonResponse = convert.jsonDecode(response.body) as Map;
setState(() {
_loading = false;
});
if (response.statusCode == 400) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(padding: EdgeInsets.all(10), backgroundColor: Colors.red, content: Text(jsonResponse['message'])));
} else if (response.statusCode == 200) {
print('user id is :' + jsonResponse['userId']);
await saveUserId(jsonResponse['userId']);
Navigator.push(context, MaterialPageRoute(builder: (context) {
return HomeScreen();
}));
}
});
}
Future হলো ডার্টের একটি কোর ক্লাস অ্যাসিনক্রোনাস অপারেশন নিয়ে কাজ করার জন্য। একটি Future অবজেক্ট একটি পোটেনশিয়াল ভ্যালু বা এরর রিপ্রেজেন্ট করে যা ভবিষ্যতে কোনো সময়ে উপলব্ধ হবে।
http.Response ক্লাস একটি সফল HTTP কল থেকে প্রাপ্ত ডেটা ধারণ করে।
উপরের কোডটি http post মেথড ব্যবহার করে create user endpoint-এ একটি পোস্ট রিকোয়েস্ট পাঠায় এবং রেসপন্সের জন্য অপেক্ষা করে।
যদি রেসপন্স স্ট্যাটাস কোড ২০০ হয়, তবে রিকোয়েস্ট সফল হয়েছে, আমরা তৈরি হওয়া UserId শেয়ারড প্রিফারেন্সে সেভ করি, এবং তারপর হোম স্ক্রিনে যাওয়া।
এই স্ক্রিনের সম্পূর্ণ সোর্স কোডের লিংক: Create Profile Screen।
একটি পোস্ট তৈরি করুন
আমাদের এন্ডপয়েন্টগুলোর একটি ইউজারকে একটি পোস্ট তৈরি করতে দেয়। স্ক্রিনটি কেমন দেখাবে:

একটি পোস্ট তৈরি করতে একটি ইউজারের দরকার:
- একটি userId
- টেক্সট
- imageUrl
মনে রাখবেন, ডেমোস্তর জন্য, আমরা একটি রেডি-মেড imageUrl ব্যবহার করছি। রিয়েল অ্যাপে, আপনাকে ইউজারকে তাদের ইমেজ পিক করতে দিতে হবে, সেটি সার্ভারে আপলোড করতে হবে, ইমেজ ইউআরএল পেতে হবে, এবং তারপর সেটি ব্যবহার করে পোস্ট তৈরি করতে হবে।
CreatePost মেথড CreateUser মেথডের মতই দেখে।
Future createPost(String userId) async {
await http
.post(Uri.parse(CREATE_USER_POST_URL),
body: convert.jsonEncode({
'userId': userId,
"postText": postTextController.text,
"postImage": _postPicUrl[i]
}))
.then((response) async {
var jsonResponse = convert.jsonDecode(response.body) as Map;
setState(() {
_loading = false;
});
if (response.statusCode == 400) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
padding: EdgeInsets.all(10),
backgroundColor: Colors.red,
content: Text(jsonResponse['message'])));
} else if (response.statusCode == 200) {
print('post id is :' + jsonResponse['id']);
Navigator.of(context).pop();
}
});
}
সকল পোস্ট লিস্ট করুন
আমাদের অ্যাপ্লিকেশনের হোম স্ক্রিন সব তৈরি হওয়া পোস্টের লিস্ট দেখাবে।
কিছু এইরকম:
স্ট্রেস-ফ্রিভাবে সকল পোস্ট রিট্রিভ করতে, আমাদের প্রথমে একটি কাস্টম ডার্ট অবজেক্ট তৈরি করতে হবে যা একটি সিঙ্গল পোস্ট রিপ্রেজেন্ট করে।
class Post {
String? postText;
String? userId;
String? createdOn;
String? id;
String? postImage;
PostAdmin? postAdmin;
Post({this.postText, this.userId, this.createdOn, this.id, this.postImage, this.postAdmin});
Post.fromJson(Map json) {
postText = json['postText'];
userId = json['userId'];
createdOn = json['createdOn'];
id = json['id'];
postImage = json['postImage'];
postAdmin = json['postAdmin'] != null ? PostAdmin.fromJson(json['postAdmin']) : null;
}
Map toJson() {
final Map data = new Map();
data['postText'] = this.postText;
data['userId'] = this.userId;
data['createdOn'] = this.createdOn;
data['id'] = this.id;
data['postImage'] = this.postImage;
if (this.postAdmin != null) {
data['postAdmin'] = this.postAdmin!.toJson();
}
return data;
}
}
class PostAdmin {
String? timestamp;
String? userId;
String? username;
String? firstName;
String? lastName;
String? profilePic;
PostAdmin({this.timestamp, this.userId, this.username, this.firstName, this.lastName, this.profilePic});
PostAdmin.fromJson(Map json) {
timestamp = json['timestamp'];
userId = json['userId'];
username = json['username'];
firstName = json['firstName'];
lastName = json['lastName'];
profilePic = json['profilePic'];
}
Map toJson() {
final Map data = new Map();
data['timestamp'] = this.timestamp;
data['userId'] = this.userId;
data['username'] = this.username;
data['firstName'] = this.firstName;
data['lastName'] = this.lastName;
data['profilePic'] = this.profilePic;
return data;
}
}
তারপর, আমরা http.Response কে সেই কাস্টম ডার্ট অবজেক্টে কনভার্ট করি।
List parsePosts(String responseBody) {
final parsed = jsonDecode(responseBody).cast
fetchPosts মেথডের রিটার্ন টাইপ হলো Future।>
যদি আপনি fetchPosts() ফাংশনটি একটি স্লো ডিভাইসে রান করেন, তবে আপনি লক্ষ্য করতে পারেন অ্যাপটি জিএসওন পার্স ও কনভার্ট করার সময় খুব সাময়িক সময়ের জন্য ফ্রিজ হয়ে যায়। এটাকে জ্যাঙ্ক বলা হয়, এবং আপনি এটাকে দূর করতে চান।
আমরা পার্সিং এবং কনভার্সনকে ব্যাকগ্রাউন্ডে মুভ করে জ্যাঙ্ক দূর করি compute ফাংশন ব্যবহার করে।
compute(parsePosts, response.body);
compute() ফাংশন ব্যয়বহুল ফাংশনগুলো একটি ব্যাকগ্রাউন্ড আইসোলেটে রান করে এবং রেজাল্ট রিটার্ন করে।
হোম স্ক্রিন ফাইলে, আমরা একটি FutureBuilder ভিজেট ব্যবহার করব আসিনক্রোনাসভাবে ডেটাবেস থেকে সকল পোস্ট লিস্ট হিসেবে গ্র্যাব করতে।
আমাদের দুটি প্যারামিটার দিতে হবে:
- যে Future-র সাথে আপনি কাজ করতে চান। এই কেসে, fetchPosts() ফাংশন থেকে রিটার্ন হওয়া ফিউচার।
একটি বিল্ডার ফাংশন যা ফ্লাটারকে বলে দেয় কী রেন্ডার করতে হবে, ফিউচারের স্টেটের উপর ভিত্তি করে: লোডিং, সাক্সেস, বা এরর।
নোট করুন snapshot.hasData শুধু তখন true রিটার্ন করে যখন স্ন্যাপশটে নন-নাল ডেটা ভ্যালু থাকে।
কারণ fetchPosts শুধু নন-নাল ভ্যালু রিটার্ন করতে পারে, ফাংশনটি এমনকি "৪০৪ Not Found" সার্ভার রেসপন্সের কেসেও এক্সেপশন থ্রো করা উচিত। এক্সেপশন থ্রো করা snapshot.hasError কে true সেট করে যা এরর মেসেজ দেখাতে ব্যবহার করা যায়।
অন্যথায়, স্পিনার দেখানো হবে।
Expanded(child: FutureBuilder>(
future: _posts,
builder: (context, snapshot) {
if (snapshot.hasData) {
List? posts = snapshot.data;
if (posts != null) {
return ListView.builder(itemBuilder: (context, index) {
return Card(
child: Container(
padding: EdgeInsets.all(10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipRRect(
borderRadius: BorderRadius.circular(1000),
child: Image.network(
posts[index].postAdmin!.profilePic!,
fit: BoxFit.cover,
height: 40,
width: 40,
),
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(posts[index].postAdmin!.username!, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
Text(posts[index].postText!),
ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
posts[index].postImage!,
fit: BoxFit.cover,
height: 150,
width: size.width,
),
),
],
),
),
)
],
),
),
);
}, itemCount: posts.length);
}
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return Container(
height: 40,
width: 40,
child: Center(child: CircularProgressIndicator(valueColor: AlwaysStoppedAnimation(Theme.of(context).colorScheme.secondary))),
);
},
))
initState মেথডে, আমরা fetchPosts কল করি:
late Future> _posts;
@override
void initState() {
super.initState();
_posts = fetchPosts(http.Client());
}
আমরা fetchPosts কে initState-এ কল করি বিল্ড মেথডে না, কারণ ফ্লাটার build() মেথডকে هرবার কল করে যখন ভিউতে যেকোনো পরিবর্তন আনে, এবং এটি অবিশ্বাস্যভাবে অনেকবার হয়। ফেচ কলকে আপনার build() মেথডে রেখে দিলে অপ্রয়োজনীয় এপিআই কলের বाढ़ আসবে এবং আপনার অ্যাপ স্লো হয়ে যাবে।
সম্পূর্ণ সোর্স কোড দেখতে পারেন।
এখনো কিছু এন্ডপয়েন্ট বাকি যাদের জন্য ইন্টারফেস তৈরি করতে হবে, কিন্তু এক্সারসাইজ ছাড়া একটি ভালো টিউটোরিয়াল কী 😂
উপসংহার
এই পোস্ট সিরিজে, আমরা দেখেছি কীভাবে আপস্ট্যাশের সাথে একটি সার্ভারলেস রেস্ট এপিআই বিল্ড করতে হয়, মোবাইল অ্যাপ্লিকেশন দিয়ে সেগুলো কনসিউম করতেছি।
আপস্ট্যাশ দিয়ে আপনি आगे কী বানাবেন, অথবা এই টিউটোরিয়ালকে আপনার ইউজ কেস অনুযায়ী কীভাবে উন্নত করবেন, সেটি দেখতে পাবো।
যদি এই পিসটি আপনার কাছে হেল্পফুল লাগে, তাহলে আপনার সোশ্যাল মিডিয়া পেজে শেয়ার করুন।
প্রশ্ন আছে? কমেন্ট করুন।
যদি কোনো ত্রুটি খুঁজে পান, আপনি জানেন কী করতে হবে। কমেন্ট করুন এবং আমি যতদ্রুত সম্ভব সেটি ফিক্স করব।
হ্যাপি কোডিং ✌🏿
রেফারেন্স
- আপস্ট্যাশ ডকস
- রেডিস
- ফ্লাটার
- ইন্টারনেট থেকে ডেটা ফেচ করা