> ## Content Index
> Fetch the complete content index at: https://arkar.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# Day 27: Pexels API, .env & Data Models
- URL: https://arkar.dev/day-27-pexels-api-env-data-models/
- Published: 2026-11-07T02:30:00.000Z
- Updated: 2026-11-07T02:30:00.000Z
- Description: Get a Pexels API key, test it from the terminal, keep it out of Git with flutter_dotenv (and learn what .env can't protect), then turn Pexels JSON into type-safe Dart models with fromJson and toJson.
- Author: Arkar Min Tun
- Tags: 100 days of flutter, flutter

ဒီနေ့ကစပြီး Pixly က internet ကနေ တကယ့် data တွေကို ယူသုံးတော့မှာ ဖြစ်ပါတယ်။ Data ယူဖို့ မစခင် ပြင်ဆင်ရမယ့် အရာ ၃ ခု ရှိပါတယ်။

1. Pexels API key ရယူပြီး API က ဘယ်လို data ပြန်ပေးလဲ ကြည့်ခြင်း
2. API key ကို code ထဲမှာ တိုက်ရိုက် မရေးဘဲ `.env` file နဲ့ ခွဲထားခြင်း
3. API က ပြန်ပေးတဲ့ JSON ကို Dart object (model) တွေ အဖြစ် ပြောင်းခြင်း

Network request တကယ် ခေါ်တာကိုတော့ မနက်ဖြန် Day 28 မှာ Dio နဲ့ လုပ်ပါမယ်။

## Pexels API Key ရယူခြင်း

1. [pexels.com](https://www.pexels.com/?ref=arkar.dev) မှာ account ဖွင့်ပြီး login ဝင်ပါ။
2. [Pexels API page](https://www.pexels.com/api/?ref=arkar.dev) ကို သွားပြီး လိုအပ်တဲ့ အချက်အလက်တွေ ဖြည့်ကာ API key တောင်းပါ။
3. ရလာတဲ့ API key ကို ဘယ်သူ့ကိုမှ မပြပါနဲ့။ GitHub လို public နေရာတွေမှာလဲ မတင်မိအောင် သတိထားပါ။

### Terminal ကနေ API ကို စမ်းကြည့်ခြင်း

Code မရေးခင် API က ဘာပြန်ပေးလဲဆိုတာ terminal ကနေ အရင် စမ်းကြည့်တာ အလေ့အကျင့် ကောင်းတခုပါ။ Pexels က API key ကို `Authorization` header ထဲမှာ ထည့်ပို့ခိုင်းပါတယ်။

```bash
curl -H "Authorization: YOUR_API_KEY" \
  "https://api.pexels.com/v1/curated?per_page=1"
```

`YOUR_API_KEY` နေရာမှာ ကိုယ့် key ကို အစားထိုးပါ။ Pexels ရဲ့ documentation အတိုင်း header value မှာ key ကိုပဲ တိုက်ရိုက် ထည့်ရတာ ဖြစ်ပြီး ရှေ့မှာ `Bearer` လို စာလုံး ခံစရာ မလိုပါဘူး။ ပြန်ရလာတဲ့ JSON ကို ချုံ့ကြည့်မယ်ဆိုရင် ဒီလိုပုံစံ ဖြစ်ပါတယ်။

```json
{
  "page": 1,
  "per_page": 1,
  "photos": [
    {
      "id": 1001,
      "width": 4000,
      "height": 6000,
      "url": "https://www.pexels.com/photo/...",
      "photographer": "...",
      "photographer_url": "https://www.pexels.com/@...",
      "photographer_id": 500,
      "avg_color": "#7A8C6E",
      "src": {
        "original": "...",
        "large2x": "...",
        "large": "...",
        "medium": "...",
        "small": "...",
        "portrait": "...",
        "landscape": "...",
        "tiny": "..."
      },
      "liked": false,
      "alt": "Green hills under a cloudy sky"
    }
  ],
  "next_page": "https://api.pexels.com/v1/curated/?page=2&per_page=1"
}
```

ဒီ structure ကနေ သတိထားစရာ ၃ ချက် ရှိပါတယ်။

- `**src**` ထဲမှာ ပုံတပုံတည်းကို အရွယ်အစား အမျိုးမျိုးနဲ့ ပေးထားပါတယ်။ Grid မှာ thumbnail ပြဖို့ `medium` လို အသေးကို သုံးပြီး detail screen မှာမှ `large2x` လို အကြီးကို သုံးမှာ ဖြစ်ပါတယ်။ Data usage နဲ့ loading speed အတွက် အရမ်း အရေးကြီးပါတယ်။
- **`avg_color`** က ပုံရဲ့ ပျမ်းမျှ အရောင်ပါ။ ပုံ load မပြီးခင် placeholder အရောင်အနေနဲ့ သုံးလို့ ရပါတယ်။
- `**next_page**` က နောက်ထပ် page ရှိမှ ပါလာပါတယ်။ Search (`/v1/search`) ရဲ့ response မှာ `total_results` (ရလဒ် စုစုပေါင်း) ပါပေမယ့် documentation ရဲ့ curated ဥပမာ response မှာတော့ `total_results` မပါပါဘူး။ ဒါကြောင့် နောက်ထပ် ပုံ ရှိသေးလားဆိုတာကို `total_results` နဲ့ မတွက်ဘဲ `next_page` ပါမပါနဲ့ ဆုံးဖြတ်တာက endpoint နှစ်ခုလုံးမှာ စိတ်ချရပါတယ်။

## API Key ကို .env နဲ့ ခွဲထားခြင်း

API key ကို code ထဲမှာ ဒီလို တိုက်ရိုက် ရေးလိုက်ရင် အလွယ်ဆုံးပါပဲ။

```dart
const apiKey = 'abc123...'; // ❌ git commit လုပ်လိုက်တာနဲ့ key ပါသွားပြီ
```

ဒါပေမယ့် project ကို GitHub ပေါ် တင်လိုက်တာနဲ့ key ပါ ပါသွားမှာ ဖြစ်ပါတယ်။ ဒါကြောင့် key တွေကို `.env` ဆိုတဲ့ သီးသန့် file ထဲမှာ ထားပြီး အဲ့ဒီ file ကို git ထဲ မထည့်ဘဲ ထားကြပါတယ်။

```bash
fvm flutter pub add flutter_dotenv
```

Project root (pubspec.yaml နဲ့ အတူတူ နေရာ) မှာ `.env` file ဖန်တီးပါ။

```
PEXELS_API_KEY=your_api_key_here
```

ပြီးရင် `.gitignore` ထဲမှာ `.env` ကို ထည့်ပြီး git ထဲ မပါသွားအောင် လုပ်ပါ။

```
.env
```

> ⚠️ `.gitignore` က git က track မလုပ်ရသေးတဲ့ file တွေကိုပဲ လျစ်လျူရှုပေးတာပါ။ `.env` ကို commit လုပ်ပြီးမှ `.gitignore` ထဲ ထည့်ရင် git က ဆက် track လုပ်နေဦးမှာ ဖြစ်ပါတယ်။ ဒီလိုဖြစ်ခဲ့ရင် `git rm --cached .env` နဲ့ tracking ကို ဖြုတ်ပေးရပါမယ်။ ဒါပေမယ့် အရင် commit တွေထဲမှာ key က ကျန်နေဆဲ ဖြစ်တဲ့အတွက် key ကို GitHub ပေါ် တင်မိခဲ့ပြီးပြီဆိုရင် Pexels မှာ key အသစ် ပြန်ထုတ်ပြီး အဟောင်းကို မသုံးတော့ပါနဲ့။

ဒါဆို project ကို clone လုပ်တဲ့သူ ဘယ် key တွေ လိုလဲ မသိနိုင်တော့ပါဘူး။ ဒီအတွက် key မပါတဲ့ `.env.example` ကိုတော့ git ထဲ ထည့်ထားပေးပါတယ်။

```
# Copy this file to .env and paste your own key from https://www.pexels.com/api/
PEXELS_API_KEY=your_api_key_here
```

`flutter_dotenv` က `.env` ကို asset အနေနဲ့ ဖတ်တာ ဖြစ်တဲ့အတွက် Day 26 မှာ လုပ်ခဲ့သလို `pubspec.yaml` ရဲ့ `assets:` ထဲမှာ ထည့်ပေးရပါမယ်။

```yaml
  assets:
    - .env
    - assets/images/
    - assets/svg/
    - assets/fonts/OFL.txt
```

App စတင်တဲ့အချိန်မှာ `.env` ကို load လုပ်ပေးရပါမယ်။

```dart
// lib/main.dart
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:pixly/config/constants.dart';
import 'package:pixly/config/theme.dart';
import 'package:pixly/screens/home_screen.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: '.env');

  // Show the Poppins font license on Flutter's licenses page.
  LicenseRegistry.addLicense(() async* {
    final license = await rootBundle.loadString('assets/fonts/OFL.txt');
    yield LicenseEntryWithLineBreaks(['Poppins'], license);
  });

  runApp(const PixlyApp());
}
```

- `main` ကို `Future<void> main() async` ပြောင်းလိုက်ပါတယ်။ Day 12 မှာ ပြောခဲ့တဲ့ `await` ကို သုံးဖို့ပါ။
- `WidgetsFlutterBinding.ensureInitialized()` \- `runApp` မခေါ်ခင် asset ဖတ်တာလိုမျိုး Flutter engine ကို သုံးရမယ့် အလုပ်တွေ လုပ်ချင်ရင် ဒီ line ကို အရင်ခေါ်ပေးရပါတယ်။
- `await dotenv.load(fileName: '.env')` \- `.env` ထဲက value တွေကို memory ထဲ ဖတ်ထားပေးပါတယ်။

နောက်ဆုံး key ကို ပြန်ယူသုံးဖို့ class လေးတခု ရေးထားပါမယ်။

```dart
// lib/config/env.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';

/// Typed access to values from the `.env` file.
class Env {
  static String get pexelsApiKey => dotenv.get('PEXELS_API_KEY');
}
```

`dotenv.get` က key မရှိရင် error throw လုပ်ပါတယ်။ `.env` ထည့်ဖို့ မေ့သွားရင် API ကို key အလွတ်နဲ့ ခေါ်ပြီး ဘာဖြစ်မှန်းမသိ ဖြစ်နေမယ့်အစား ချက်ချင်း သိရတဲ့အတွက် ပိုကောင်းပါတယ်။

### ⚠️ .env က ဘာကို မကာကွယ်ပေးနိုင်လဲ

ဒီအချက်ကို သေချာ နားလည်ထားဖို့ အရမ်း အရေးကြီးပါတယ်။ `.env` က key ကို **git ထဲ မပါအောင်** ကာကွယ်ပေးတာပါ။ App ထဲမှာ **လျှို့ဝှက်ထားပေးတာ မဟုတ်ပါဘူး**။ `.env` ကို asset အနေနဲ့ ထည့်လိုက်တဲ့အတွက် build လုပ်ထားတဲ့ APK ဒါမှမဟုတ် IPA file ကို ဖြည်ပြီး ကြည့်လိုက်တာနဲ့ key ကို ပြန်ဖတ်လို့ ရနေမှာ ဖြစ်ပါတယ်။

- Pexels key လို အခမဲ့ပြီး rate limit ရှိတဲ့ key အတွက် ဒီ level က လေ့လာဖို့ လုံလောက်ပါတယ်။
- ငွေကြေး ပတ်သက်တဲ့ key, admin key လိုမျိုး တကယ် လျှို့ဝှက်ရမယ့် key တွေကို mobile app ထဲ **ဘယ်တော့မှ** မထည့်ပါနဲ့။ အဲ့ဒီလို အခြေအနေမှာ ကိုယ့် backend server ကနေ ကြားခံ ခေါ်ပေးရပါမယ်။ App က ကိုယ့် server ကို ခေါ်၊ server က key နဲ့ third-party API ကို ခေါ်တဲ့ ပုံစံပါ။

## JSON ကနေ Dart Model တွေ

API က ပြန်ပေးတဲ့ JSON ကို decode လုပ်လိုက်ရင် `Map<String, dynamic>` ရပါတယ်။ ဒါကို app တခုလုံးမှာ `photo['photographer']` လို ဟိုသုံး ဒီသုံး လုပ်နေမယ်ဆိုရင် key နာမည် စာလုံးတလုံး မှားတာနဲ့ run မှ error တက်မှာ ဖြစ်ပြီး ဘယ် field က ဘယ် type လဲဆိုတာကိုလဲ editor က မသိပါဘူး။ ဒါကြောင့် JSON ကို Day 7 မှာ လေ့လာခဲ့တဲ့ class တွေ အဖြစ် ပြောင်းပြီးမှ သုံးပါမယ်။ ဒီလို class တွေကို **model** လို့ ခေါ်ပါတယ်။

### PhotoSrc

```dart
// lib/models/photo_src.dart
/// The different image sizes Pexels gives us for one photo.
class PhotoSrc {
  final String original;
  final String large2x;
  final String large;
  final String medium;
  final String small;
  final String portrait;
  final String landscape;
  final String tiny;

  const PhotoSrc({
    required this.original,
    required this.large2x,
    required this.large,
    required this.medium,
    required this.small,
    required this.portrait,
    required this.landscape,
    required this.tiny,
  });

  factory PhotoSrc.fromJson(Map<String, dynamic> json) {
    return PhotoSrc(
      original: json['original'] as String? ?? '',
      large2x: json['large2x'] as String? ?? '',
      large: json['large'] as String? ?? '',
      medium: json['medium'] as String? ?? '',
      small: json['small'] as String? ?? '',
      portrait: json['portrait'] as String? ?? '',
      landscape: json['landscape'] as String? ?? '',
      tiny: json['tiny'] as String? ?? '',
    );
  }

  Map<String, dynamic> toJson() => {
    'original': original,
    'large2x': large2x,
    'large': large,
    'medium': medium,
    'small': small,
    'portrait': portrait,
    'landscape': landscape,
    'tiny': tiny,
  };
}
```

- `**factory PhotoSrc.fromJson(...)**` \- Day 7 က named constructor လိုပဲ ဖြစ်ပြီး `Map` တခုကို လက်ခံပြီး `PhotoSrc` object တခု ပြန်ထုတ်ပေးပါတယ်။
- `**json['medium'] as String? ?? ''**` \- Day 5 က null safety ကို ပြန်သုံးထားတာပါ။ API က field တခုခု မပို့ခဲ့ရင် `null` ဖြစ်နိုင်တဲ့အတွက် အရင် `String?` (null ဖြစ်နိုင်တဲ့ String) အဖြစ် cast လုပ်ပြီး null ဖြစ်ခဲ့ရင် `??` နဲ့ string အလွတ် default ပေးထားပါတယ်။ ဒါမှ field တခု ပျောက်နေရုံနဲ့ app crash မဖြစ်တော့မှာပါ။
- `**toJson()**` \- object ကို `Map` ပြန်ပြောင်းပေးတာပါ။ Day 35 မှာ bookmark လုပ်ထားတဲ့ ပုံတွေကို device ထဲ သိမ်းတဲ့အခါ ပြန်သုံးမှာ ဖြစ်ပါတယ်။

### Photo

```dart
// lib/models/photo.dart
import 'package:pixly/models/photo_src.dart';

class Photo {
  final int id;
  final int width;
  final int height;
  final String url;
  final String photographer;
  final String photographerUrl;
  final String avgColor;
  final String alt;
  final PhotoSrc src;

  const Photo({
    required this.id,
    required this.width,
    required this.height,
    required this.url,
    required this.photographer,
    required this.photographerUrl,
    required this.avgColor,
    required this.alt,
    required this.src,
  });

  /// width ÷ height of the original photo, handy for layouts.
  double get aspectRatio => height == 0 ? 1 : width / height;

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      id: json['id'] as int,
      width: json['width'] as int? ?? 0,
      height: json['height'] as int? ?? 0,
      url: json['url'] as String? ?? '',
      photographer: json['photographer'] as String? ?? 'Unknown',
      photographerUrl: json['photographer_url'] as String? ?? '',
      avgColor: json['avg_color'] as String? ?? '#9E9E9E',
      alt: json['alt'] as String? ?? '',
      src: PhotoSrc.fromJson(json['src'] as Map<String, dynamic>),
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id,
    'width': width,
    'height': height,
    'url': url,
    'photographer': photographer,
    'photographer_url': photographerUrl,
    'avg_color': avgColor,
    'alt': alt,
    'src': src.toJson(),
  };
}
```

သတိထားကြည့်စရာတွေကတော့

- JSON မှာ `photographer_url` (snake\_case) ဖြစ်ပေမယ့် Dart မှာ `photographerUrl` (camelCase) လို့ ပြောင်းသုံးထားပါတယ်။ Dart ရဲ့ naming convention အတိုင်း ဖြစ်အောင်ပါ။ `fromJson`/`toJson` ထဲမှာပဲ JSON key အစစ်ကို သုံးထားတာ ဖြစ်ပါတယ်။
- `id` ကတော့ photo တိုင်းမှာ အမြဲ ပါရမယ့် field ဖြစ်တဲ့အတွက် default မပေးဘဲ `as int` နဲ့ တိုက်ရိုက် cast လုပ်ထားပါတယ်။ `id` မပါတဲ့ data ဆိုရင် မှားနေတဲ့ data ဖြစ်တဲ့အတွက် error တက်တာက ပိုကောင်းပါတယ်။
- `src` က nested object ဖြစ်တဲ့အတွက် `PhotoSrc.fromJson` ကို ဆက်ခေါ်ထားပါတယ်။
- `aspectRatio` getter ကတော့ မူလ ပုံရဲ့ width ÷ height ဖြစ်ပါတယ်။ Day 24 မှာ ပြောခဲ့တဲ့ `childAspectRatio` လိုပဲ width/height ratio ဖြစ်ပြီး detail screen မှာ ပုံကို အချိုးမပျက် ပြဖို့ သုံးမှာပါ။

### PhotosPage

API က ပုံတွေကို တခါတည်း အကုန်မပေးဘဲ page လိုက် ခွဲပေးပါတယ်။ page တခုစာ data ကို ကိုယ်စားပြုဖို့ model တခု ထပ်လိုပါတယ်။

```dart
// lib/models/photos_page.dart
import 'package:pixly/models/photo.dart';

/// One page of results from /curated or /search.
class PhotosPage {
  final int page;
  final int perPage;
  final List<Photo> photos;
  final int? totalResults;
  final String? nextPage;

  const PhotosPage({
    required this.page,
    required this.perPage,
    required this.photos,
    this.totalResults,
    this.nextPage,
  });

  /// Pexels only sends `next_page` when there is another page.
  bool get hasMore => nextPage != null;

  factory PhotosPage.fromJson(Map<String, dynamic> json) {
    final photos = (json['photos'] as List<dynamic>? ?? [])
        .map((item) => Photo.fromJson(item as Map<String, dynamic>))
        .toList();

    return PhotosPage(
      page: json['page'] as int? ?? 1,
      perPage: json['per_page'] as int? ?? photos.length,
      photos: photos,
      totalResults: json['total_results'] as int?,
      nextPage: json['next_page'] as String?,
    );
  }
}
```

- `photos` list ကို ပြောင်းတဲ့နေရာမှာ Day 10 က `.map()` နဲ့ `.toList()` ကို သုံးထားပါတယ်။ JSON list ထဲက item တခုချင်းစီကို `Photo.fromJson` နဲ့ `Photo` object ပြောင်းပေးတာပါ။
- `totalResults` နဲ့ `nextPage` က response မှာ ပါချင်မှ ပါမှာ ဖြစ်တဲ့အတွက် nullable (`int?`, `String?`) ထားပါတယ်။
- `hasMore` getter က `next_page` ပါမပါကို ကြည့်ပြီး နောက်ထပ် page ရှိမရှိ ပြောပေးပါတယ်။ Day 31 မှာ infinite scroll လုပ်တဲ့အခါ ဒီ getter ကို အဓိက သုံးမှာ ဖြစ်ပါတယ်။

> 💡 JSON field များလာတဲ့အခါ `fromJson`/`toJson` တွေကို လက်နဲ့ ရေးရတာ ပင်ပန်းပြီး မှားလွယ်ပါတယ်။ ဒါကို code generation နဲ့ အလိုအလျောက် ထုတ်ပေးတဲ့ `json_serializable` နဲ့ `freezed` အကြောင်းကို Day 45 မှာ ဆက်လေ့လာမှာ ဖြစ်ပါတယ်။ အခုတော့ JSON parsing ဘယ်လို အလုပ်လုပ်လဲ နားလည်အောင် လက်နဲ့ အရင် ရေးကြည့်တာ ဖြစ်ပါတယ်။

## Model တွေကို စမ်းကြည့်ခြင်း

Network request မရေးရသေးခင် model တွေ မှန်မမှန် စမ်းဖို့ Pexels response ပုံစံအတိုင်း sample JSON file တွေ (`test/fixtures/`) ပြင်ဆင်ပြီး test လေးတွေ ရေးထားပါတယ်။ (Sample data ထဲက ID, နာမည်, URL တွေက test အတွက် လုပ်ထားတာ ဖြစ်ပြီး Pexels က ပုံအစစ်တွေ မဟုတ်ပါဘူး။)

Fixture file တွေက Pexels response ပုံစံအတိုင်းပါပဲ။ ဥပမာ `test/fixtures/curated_last_page.json` က နောက်ဆုံး page ဖြစ်တဲ့အတွက် `next_page` မပါဘဲ `prev_page` ပဲ ပါပါတယ်။

```json
{
  "page": 3,
  "per_page": 12,
  "photos": [ ... ],
  "prev_page": "https://api.pexels.com/v1/curated/?page=2&per_page=12"
}
```

```dart
// test/models_test.dart
import 'dart:convert';
import 'dart:io';

import 'package:flutter_test/flutter_test.dart';
import 'package:pixly/models/photo.dart';
import 'package:pixly/models/photos_page.dart';

Map<String, dynamic> fixture(String name) =>
    json.decode(File('test/fixtures/$name.json').readAsStringSync())
        as Map<String, dynamic>;

void main() {
  test('parses a curated page (no total_results, has next_page)', () {
    final page = PhotosPage.fromJson(fixture('curated_page1'));
    expect(page.page, 1);
    expect(page.perPage, 12);
    expect(page.photos, hasLength(12));
    expect(page.totalResults, isNull);
    expect(page.hasMore, isTrue);
  });

  test('last page has no next_page => hasMore is false', () {
    final page = PhotosPage.fromJson(fixture('curated_last_page'));
    expect(page.hasMore, isFalse);
  });
}
```

`fixture()` helper က `test/fixtures/` ထဲက JSON file ကို ဖတ်ပြီး `Map` ပြန်ပေးတာ ဖြစ်ပါတယ်။ Project ထဲမှာတော့ ဒီ test တွေအပြင် search response နဲ့ `toJson`/`fromJson` round trip ကို စစ်တဲ့ test တွေလဲ ထပ်ပါပါတယ်။

`fvm flutter test` နဲ့ run လိုက်ရင် test အားလုံး pass ဖြစ်ရပါမယ်။ Testing အကြောင်းကို Day 86 မှာ အသေးစိတ် ပြောမှာ ဖြစ်လို့ ဒီနေ့တော့ "model တွေ JSON ကို မှန်မှန်ကန်ကန် ပြောင်းပေးလား" ဆိုတာ စစ်တဲ့ နည်းလမ်းတခုအနေနဲ့ပဲ မှတ်ထားပါ။

ဒီနေ့ပြီးသွားတဲ့အခါ project ထဲမှာ ဒီလို file တွေ ရှိနေပါပြီ။

```
lib/
├── config/
│   ├── assets.dart
│   ├── constants.dart
│   ├── env.dart        ← new
│   └── theme.dart
├── models/             ← new
│   ├── photo.dart
│   ├── photo_src.dart
│   └── photos_page.dart
├── screens/
│   └── home_screen.dart
├── widgets/
│   └── empty_state.dart
└── main.dart
```

**Source code:** ဒီနေ့ရဲ့ code အပြည့်အစုံကို [GitHub](https://github.com/arkarmintun1/100-days-of-flutter/tree/main/day27/pixly?ref=arkar.dev) မှာ run ကြည့်လို့ ရပါတယ်။

---

ဒီနေ့ Day 27 အတွက်ကတော့ ဒီလောက်ပဲ ဖြစ်ပါတယ်။ အဆုံးထိ ဖတ်ပေးတဲ့အတွက် အများကြီး ကျေးဇူးတင်ပါတယ်။ နားမလည်တာတွေ အဆင်မပြေတာတွေ ရှိခဲ့ရင်လဲ အောက်မှာပေးထားတဲ့ discord server ထဲမှာ လာရောက်ဆွေးနွေးနိုင်ပါတယ်။ နောက်နေ့တွေမှာလဲ ဆက်လက်ပြီး sharing လုပ်သွားပေးသွားမှာ ဖြစ်တဲ့အတွက် subscribe လုပ်ထားဖို့ ဖိတ်ခေါ်ပါတယ်။

- Youtube: [https://www.youtube.com/@arkarmintun](https://www.youtube.com/@arkarmintun?ref=arkar.dev)
- Newsletter: <https://arkar.dev/>
- Discord: [https://discord.gg/3xUJ6k6dkH](https://discord.gg/3xUJ6k6dkH?ref=arkar.dev)