Thuta Learning
API Integration & Webhooks
ProjectsWeb Developmentintermediate

Project: Third-Party Integration အပြည့်အစုံ

ဒီခန်းပြီးရင် ဘာတတ်သွားမလဲ

  • Project: Third-Party Integration အပြည့်အစုံ concept ကို နားလည်ရှင်းပြနိုင်ရန်
  • Diagram ကို ဖတ်ပြီး request/response (သို့) event flow ဘယ်လိုစီးဆင်းသလဲ ခြေရာခံနိုင်ရန်
  • ကိုယ့် ကိုယ်ပိုင် API integration အတွက် ဘယ်လို အသုံးချသင့်သလဲ ရှင်းပြနိုင်ရန်

နားလည်ထားရမယ့် အချက်

ဒီ capstone project က course ထဲက reliability အပိုင်းအားလုံးကို pipeline တစ်ခုတည်းထဲ ပေါင်းစပ်ပေးပါတယ် — frontend က third-party API ကနေ data လိုချင်ပေမယ့် secret key က browser ဆီ ရောက်လို့မရဘူးမို့ backend က proxy အနေနဲ့ ကြားထဲ ရပ်ပါတယ်။

Secret management ကတော့ credential ကို backend environment ထဲမှာထားပြီး server-side ကနေပဲ request ကို ချိတ်ပေးတာပါ — ဘာမှားနေနေ log line ထဲ ဘယ်တော့မှ မပေါ်စေရပါဘူး။

Response validation ကတော့ status 200 ရုံနဲ့ success ဖြစ်တယ်လို့ မယူဆနိုင်ပါဘူး — body shape ကို တကယ်စစ်ပြီးမှ ယုံပါ၊ misconfigure ဖြစ်နေတဲ့ third party က 200 နဲ့ payload ပျက်နေတာ ပြန်ပေးနိုင်ပါတယ်။

Timeouts, retries, နဲ့ cache

Transient failure ကို bounded retry + backoff နဲ့ ကိုင်တွယ်ပါ၊ third party ကို hammer မလုပ်ဘဲ recover ဖြစ်ဖို့ အချိန်ပေးပါ။ Fresh, validated data ရှိပြီးသားဆိုရင် cache ကနေ ပြန်ပေးပြီး network call ကို skip လုပ်ပါ။

  • Cache ကို အရင်ဆုံး စစ်ပါ။
  • Credential ကို real network call တစ်ခုအတွက်ပဲ ထည့်ပါ။
  • Cache မလုပ်ခင် response ကို validate လုပ်ပါ။
  • Transient failure ကိုပဲ retry လုပ်ပါ၊ validation failure ကို ဘယ်တော့မှ retry မလုပ်ပါနဲ့။
text
THIRD-PARTY INTEGRATION PIPELINE
--------------------------------
Frontend
  |
  | request (e.g. GET /exchange-rate)
  v
Backend:
  1. Check cache -- hit --> skip straight to step 6
  2. Attach secret credential (value never logged)
  3. Call third-party API
  4. Validate response -- invalid --> return error, do not cache
  5. Transient failure? -- yes --> backoff, retry (max 3 attempts)
                        -- no  --> continue
  6. Store result in cache, return clean result
  |
  v
Frontend (gets clean result, secret never exposed)

လက်တွေ့ scenario နဲ့ ချိတ်ကြည့်မယ်

Cache စစ်ပါ

Request ရဲ့ method/path ကနေ cache key တွက်ပြီး TTL ပါတဲ့ cache ကို စစ်ပါ — fresh hit ရှိရင် ချက်ချင်း return ပါ။

Credential ချိတ်ပါ

Cache miss ဖြစ်မှသာ request copy ပေါ်မှာ credential ချိတ်ပါ — secret value ကို log ထဲ ဘယ်တော့မှ မထည့်ပါနဲ့။

Bounded retry နဲ့ ခေါ်ပါ

Attempt သုံးကြိမ်အထိ retry ပါ၊ transient failure တစ်ကြိမ်စီ backoff delay ကို နှစ်ဆတိုးပါ။

Response validate လုပ်ပါ

Transient error မရှိတဲ့ response ကို validateResponse နဲ့ ဖြတ်ပါ — invalid ဆိုရင် error ချက်ချင်းပြန်ပြီး ဘယ်တော့မှ cache မလုပ်ပါနဲ့။

Cache ထဲ ရေးသိမ်းပါ

Success ဖြစ်ပြီး validate ပါဖြစ်တဲ့ response ကိုပဲ cache ထဲ ရေးပြီး final result အဖြစ် ပြန်ပေးပါ။

Log array ကို ဖတ်ပါ

Scenario တစ်ခုစီရဲ့ log ကို ဖတ်ကြည့်ရင် ဘယ်အဆင့်က run ဖြစ်ခဲ့ပြီး ဘာကြောင့်ဆိုတာ တိတိကျကျ တွေ့ရပါလိမ့်မယ် — production debugging နည်းလည်း ဒီအတိုင်းပါပဲ။

အတူတူ စမ်းရေးကြည့်မယ်

javascript
// A deterministic stand-in for setTimeout, so backoff delays are
// simulated (logged) instead of actually pausing the test run.
function fakeDelay(ms, log) {
  log.push(`  waited ${ms}ms (backoff)`);
}

const cache = new Map();
const CACHE_TTL_MS = 60000;

// Never log the secret itself -- only that a credential was attached.
function addCredential(request, secretStore) {
  const secret = secretStore.THIRD_PARTY_KEY;
  return { ...request, headers: { ...request.headers, Authorization: `Bearer ${secret}` } };
}

function validateResponse(res) {
  if (typeof res.status !== 'number') return { valid: false, reason: 'missing_status' };
  if (res.status >= 200 && res.status < 300) {
    if (!res.body || typeof res.body.total !== 'number') {
      return { valid: false, reason: 'malformed_body' };
    }
    return { valid: true };
  }
  return { valid: false, reason: `bad_status_${res.status}` };
}

function fetchWithReliability(request, mockApiCall, secretStore, now = Date.now()) {
  const log = [];
  const cacheKey = `${request.method} ${request.path}`;

  const cached = cache.get(cacheKey);
  if (cached && now - cached.storedAt < CACHE_TTL_MS) {
    log.push('cache hit, skipping network call');
    return { ok: true, source: 'cache', data: cached.data, log };
  }
  log.push('cache miss');

  const signedRequest = addCredential(request, secretStore);
  log.push('attached credential (value not logged)');

  const maxAttempts = 3;
  let lastError = null;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    log.push(`attempt ${attempt}: calling third-party API`);
    const res = mockApiCall(signedRequest, attempt);

    if (res.transientError) {
      lastError = 'transient_error';
      log.push(`attempt ${attempt} failed with a transient error`);
      if (attempt < maxAttempts) {
        fakeDelay(2 ** attempt * 100, log);
        continue;
      }
      break;
    }

    const check = validateResponse(res);
    if (!check.valid) {
      log.push(`attempt ${attempt} returned an invalid response: ${check.reason}`);
      return { ok: false, source: 'network', error: check.reason, log };
    }

    cache.set(cacheKey, { data: res.body, storedAt: now });
    log.push('response validated and cached');
    return { ok: true, source: 'network', data: res.body, log };
  }

  return { ok: false, source: 'network', error: lastError, log };
}

// --- Fixed, deterministic scenarios -------------------------------------
const secretStore = { THIRD_PARTY_KEY: 'sk_live_should_never_be_logged' };
const request = { method: 'GET', path: '/exchange-rate', headers: {} };

console.log('Scenario 1: first-time call succeeds immediately');
let callCount = 0;
const alwaysSucceeds = () => {
  callCount++;
  return { status: 200, body: { total: 1 } };
};
console.log(fetchWithReliability(request, alwaysSucceeds, secretStore, 1000));

console.log('\nScenario 2: cache hit (same request, 5 seconds later)');
console.log(fetchWithReliability(request, alwaysSucceeds, secretStore, 6000));

console.log('\nScenario 3: transient failure on attempt 1, succeeds on attempt 2');
const differentRequest = { method: 'GET', path: '/inventory-count', headers: {} };
const flakyOnce = (req, attempt) => {
  if (attempt === 1) return { transientError: true };
  return { status: 200, body: { total: 42 } };
};
console.log(fetchWithReliability(differentRequest, flakyOnce, secretStore, 100000));
You should see
Scenario 1 (ပထမဆုံးအကြိမ် success) က { ok: true, source: 'network', data: { total: 1 } } ပြန်ပေးပြီး log မှာ cache miss, credential ချိတ်ခြင်း, attempt 1, 'response validated and cached' ဆိုတာ တွေ့ရပါတယ်။ Scenario 2 (ထပ်ခိုး request) က { ok: true, source: 'cache', data: { total: 1 } } ပြန်ပေးပြီး log မှာ 'cache hit, skipping network call' တစ်ခုတည်းပဲ ပါပါတယ် — credential ဘယ်တော့မှ မချိတ်ဘဲ network call လုံးဝမလုပ်ပါဘူး။ Scenario 3 (transient failure ပြီး success) က { ok: true, source: 'network', data: { total: 42 } } ပြန်ပေးပြီး log မှာ attempt 1 fail ဖြစ်ခြင်း, 200ms backoff စောင့်ခြင်း, ပြီးရင် attempt 2 success ဖြစ်ခြင်း တွေ့ရပါတယ်။

၅ မိနစ် စမ်းကြည့်

maxAttempts parameter ထပ်ထည့်ပြီး attempt တိုင်း transient error နဲ့ fail ဖြစ်တဲ့ scenario တစ်ခု ထပ်ထည့်ပါ — fetchWithReliability က attempt သုံးကြိမ်ပြီးနောက် လက်လျှော့ပြီး အမြဲ retry မလုပ်ဘဲ { ok: false, error: 'transient_error' } ပြန်ပေးကြောင်း စစ်ဆေးပါ။

သတိလေးတစ်ချက်

Response ကို validate မလုပ်ခင် cache ထဲ ရေးထားတာ — malformed ဒါမှမဟုတ် error payload တစ်ခုက TTL မကုန်ခင် request နောက်ဆက်တွဲအားလုံးကို cache ကနေပဲ ဆက်ဝန်ဆောင်ပေးနေမှာပါ။

Failure အမျိုးအစားတိုင်း, validation failure အပါအဝင် retry လုပ်တာ — data မှားကို retry လုပ်တာက attempt တွေနဲ့ အချိန်ကိုပဲ ဖြုန်းစေပြီး ရလဒ်ကို ဘယ်တော့မှ မပြောင်းလဲပေးပါဘူး။

AWS Architecture Blog: Exponential Backoff and JitterAPI Integration & Webhooks

ဒီနေရာမှာ လူအများမှားတတ်တယ်

  • Response ကို validate မလုပ်ခင် cache ထဲ ရေးထားတာ — malformed ဒါမှမဟုတ် error payload တစ်ခုက TTL မကုန်ခင် request နောက်ဆက်တွဲအားလုံးကို cache ကနေပဲ ဆက်ဝန်ဆောင်ပေးနေမှာပါ။
  • Failure အမျိုးအစားတိုင်း, validation failure အပါအဝင် retry လုပ်တာ — data မှားကို retry လုပ်တာက attempt တွေနဲ့ အချိန်ကိုပဲ ဖြုန်းစေပြီး ရလဒ်ကို ဘယ်တော့မှ မပြောင်းလဲပေးပါဘူး။
  • API Tutorial (apiguide) ကို မလေ့လာရသေးရင် ဒီ course ကို စမလိုက်ခင် အရင် ပြီးအောင် လေ့လာထားသင့်ပါတယ် — ဒီ course က REST/HTTP/Auth အခြေခံတွေကို ထပ်မသင်ဘဲ webhook, testing, reliability, integration architecture တို့ကိုသာ ဆက်လက် တည်ဆောက်ပါတယ်။

လေ့ကျင့်ခန်း

maxAttempts parameter ထပ်ထည့်ပြီး attempt တိုင်း transient error နဲ့ fail ဖြစ်တဲ့ scenario တစ်ခု ထပ်ထည့်ပါ — fetchWithReliability က attempt သုံးကြိမ်ပြီးနောက် လက်လျှော့ပြီး အမြဲ retry မလုပ်ဘဲ { ok: false, error: 'transient_error' } ပြန်ပေးကြောင်း စစ်ဆေးပါ။

You'll know it worked when: Scenario 1 (ပထမဆုံးအကြိမ် success) က { ok: true, source: 'network', data: { total: 1 } } ပြန်ပေးပြီး log မှာ cache miss, credential ချိတ်ခြင်း, attempt 1, 'response validated and cached' ဆိုတာ တွေ့ရပါတယ်။ Scenario 2 (ထပ်ခိုး request) က { ok: true, source: 'cache', data: { total: 1 } } ပြန်ပေးပြီး log မှာ 'cache hit, skipping network call' တစ်ခုတည်းပဲ ပါပါတယ် — credential ဘယ်တော့မှ မချိတ်ဘဲ network call လုံးဝမလုပ်ပါဘူး။ Scenario 3 (transient failure ပြီး success) က { ok: true, source: 'network', data: { total: 42 } } ပြန်ပေးပြီး log မှာ attempt 1 fail ဖြစ်ခြင်း, 200ms backoff စောင့်ခြင်း, ပြီးရင် attempt 2 success ဖြစ်ခြင်း တွေ့ရပါတယ်။

Project: Third-Party Integration အပြည့်အစုံ | Thuta Learning