Case Study/กรณีศึกษาการใช้งานจริง

goldprice.dev คำนวณราคาทองคำเป็นสกุลเงินท้องถิ่นอย่างไร

goldprice.dev ผสานราคาทองคำในสกุลดอลลาร์สหรัฐเข้ากับอัตราแลกเปลี่ยนจาก exchangerate.dev เพื่อให้บริการราคาทองคำในสกุลเงินท้องถิ่น โดยไม่ปิดบังขอบเขตความสดใหม่ของข้อมูล

MMexchangerate.dev·Jul 16, 2026·อ่าน 7 นาที

goldprice.dev และ exchangerate.dev เป็นผลิตภัณฑ์พี่น้องที่ดำเนินการโดยบริษัทเดียวกัน ในระบบใช้งานจริง goldprice.dev เป็นผู้รับผิดชอบสัญญาราคาทองคำ ส่วน exchangerate.dev จัดหาส่วนของอัตราแลกเปลี่ยนสำหรับสกุลเงินลอยตัวที่รองรับ ขอบเขตนี้มีความสำคัญ: ราคาทองคำในสกุลท้องถิ่นประกอบด้วยค่าสังเกตตลาดสองจุด และความสดใหม่ของค่าหนึ่งไม่สามารถทำให้อีกค่าหนึ่งสดใหม่ตามไปด้วย

Key points
goldprice.dev เป็นผู้รับผิดชอบราคาทองคำและการตอบกลับการแปลงค่าแบบสาธารณะ ส่วน exchangerate.dev จัดหาส่วนของอัตราแลกเปลี่ยน
endpoint สาธารณะ /v1/convert ของ goldprice.dev คือเส้นทางใช้งานจริงแบบเรียกครั้งเดียว
นักพัฒนาสามารถเรียก API ทั้งสองแยกกันได้ เมื่อต้องการที่มาของข้อมูลที่ตรวจสอบย้อนกลับได้
จัดเก็บ computed_at ของทองคำ และ data_updated_at, timestamp, source, market_session ของอัตราแลกเปลี่ยนแยกจากกัน
ราคาที่แปลงค่าแล้วเป็นมูลค่าตลาดเชิงบ่งชี้ ไม่ใช่ราคาสำหรับการซื้อขายจริงจากผู้ค้าหรือราคาชำระบัญชี

ขอบเขตของระบบใช้งานจริง

goldprice.dev เริ่มต้นด้วยค่าสังเกตราคาโลหะในสกุลดอลลาร์สหรัฐ ส่วน exchangerate.dev ให้ค่าสังเกตอัตราแลกเปลี่ยนจากดอลลาร์สหรัฐไปยังสกุลเงินท้องถิ่นที่สอดคล้องกันสำหรับสกุลเงินลอยตัวที่รองรับ จากนั้น goldprice.dev จะเป็นผู้รับผิดชอบสัญญาการแปลงค่าเฉพาะโลหะ ซึ่งรวมถึงหน่วย สัญลักษณ์ที่รองรับ การตรวจสอบความถูกต้อง และการตอบกลับขั้นสุดท้าย

นี่คือการผสานระบบระหว่างผลิตภัณฑ์พี่น้องที่เปิดเผยอย่างชัดเจน ไม่ใช่การรับรองจากลูกค้าอิสระ คุณค่าของกรณีศึกษานี้อยู่ที่การใช้งานจริง: API อัตราแลกเปลี่ยนจัดหาส่วนข้อมูลใช้งานจริงส่วนหนึ่ง และผลิตภัณฑ์ที่นำไปใช้ยังคงรับผิดชอบต่อขอบเขตงานของตัวเองอยู่

สูตรการแปลงค่า

ทองคำมักถูกเสนอราคาเป็นดอลลาร์สหรัฐต่อทรอยออนซ์ ขณะที่การแสดงผลในสกุลท้องถิ่นมักต้องการจำนวนเงินต่อกรัม ให้แปลงหน่วยน้ำหนักก่อน แล้วจึงคูณด้วยอัตราแลกเปลี่ยนดอลลาร์สหรัฐ:

formula · USD/oz to local currency/gramcopy
const GRAMS_PER_TROY_OZ = 31.1035;

function localGoldPerGram(usdPerTroyOz, usdToLocalRate) {
  return (usdPerTroyOz / GRAMS_PER_TROY_OZ) * usdToLocalRate;
}

ค่าคงที่ของหน่วยน้ำหนักนั้นตายตัว แต่ข้อมูลนำเข้าจากตลาดทั้งสองไม่ใช่: ทั้งราคาทองคำและอัตราแลกเปลี่ยนต่างมีเวลาสังเกตและกฎความสดใหม่เป็นของตัวเอง

เส้นทางใช้งานจริงแบบเรียกครั้งเดียว

สำหรับผู้เรียกใช้งาน ขอบเขตของระบบใช้งานจริงคือ goldprice.dev `/v1/convert` ซึ่งรวมส่วนของโลหะและอัตราแลกเปลี่ยนไว้เบื้องหลัง endpoint เดียวที่รู้จักโลหะ และไม่ต้องใช้ API key ตัวอย่างนี้ร้องขอมูลค่าของทองคำหนึ่งกรัมเป็นสกุลเงินรูเปียห์อินโดนีเซีย:

javascript · one-request conversioncopy
const params = new URLSearchParams({
  from: "XAU",
  to: "IDR",
  amount: "1",
  unit: "gram",
});

const response = await fetch(
  `https://api.goldprice.dev/v1/convert?${params}`,
);

if (!response.ok) {
  throw new Error(`goldprice.dev returned ${response.status}`);
}

const conversion = await response.json();
console.log(conversion.result, conversion.to, conversion.timestamp);

เส้นทางนี้ทำให้สัญญาของผู้เรียกใช้งานเรียบง่าย: หนึ่งคำขอ หนึ่งจำนวน หนึ่งหน่วยโลหะ และสกุลเงินปลายทางหนึ่งสกุล ค่า timestamp เพียงค่าเดียวไม่ได้เป็นหลักฐานยืนยันความสดใหม่ของทั้งสองส่วนตลาดแยกจากกัน ดังนั้นผู้ใช้งานที่ต้องตรวจสอบความสดใหม่ของอัตราแลกเปลี่ยนควรใช้เส้นทางแบบสองส่วนด้านล่างแทน

การผสานระบบแบบสองส่วนที่ตรวจสอบย้อนกลับได้

เรียก API ทั้งสองตัวเมื่อคุณต้องการเก็บ timestamp ของแต่ละแหล่งข้อมูล แคชค่านำเข้าแยกจากกัน หรืออธิบายได้ว่าส่วนใดที่ข้อมูลเก่าไป goldprice.dev spot จัดหาราคาทองคำดอลลาร์สหรัฐต่อทรอยออนซ์ ส่วน exchangerate.dev จัดหาอัตราแลกเปลี่ยนดอลลาร์สหรัฐไปยังสกุลเงินท้องถิ่น

javascript · explicit gold and FX legscopy
const GRAMS_PER_TROY_OZ = 31.1035;

async function getGoldInCurrencies(currencies) {
  const symbols = currencies.join(",");
  const [spotResponse, fxResponse] = await Promise.all([
    fetch("https://api.goldprice.dev/v1/spot/XAU-USD-SPOT"),
    fetch(`https://api.exchangerate.dev/v1/latest/USD?symbols=${symbols}`),
  ]);

  if (!spotResponse.ok || !fxResponse.ok) {
    throw new Error("A market-data request failed");
  }

  const spot = await spotResponse.json();
  const fx = await fxResponse.json();
  const usdPerGram = Number(spot.price) / GRAMS_PER_TROY_OZ;

  return {
    goldComputedAt: spot.computed_at,
    fxDataUpdatedAt: fx.data_updated_at,
    fxResponseTimestamp: fx.timestamp,
    fxSource: fx.source,
    fxMarketSession: fx.market_session,
    prices: Object.fromEntries(
      currencies.map((currency) => [
        currency,
        usdPerGram * Number(fx.rates[currency]),
      ]),
    ),
  };
}

const result = await getGoldInCurrencies(["EUR", "IDR", "JPY"]);
timestamp ของการตอบกลับ ไม่ใช่ timestamp ของตลาด
เก็บรักษา spot.computed_at ไว้สำหรับค่าสังเกตราคาทองคำ และ fx.data_updated_at สำหรับค่าสังเกตอัตราแลกเปลี่ยนที่เก่าที่สุดที่มีส่วนร่วม ค่า timestamp ของอัตราแลกเปลี่ยนคือเวลาที่สร้างการตอบกลับ ส่วน source และ market_session เพิ่มบริบทของประเภทข้อมูลและช่วงเวลาซื้อขาย อย่าแทนที่ฟิลด์เหล่านี้ด้วย Date.now()

เหตุใดทั้งสองบริการจึงยังคงแยกจากกัน

การผสานระบบนี้ไม่ได้ทำให้ exchangerate.dev กลายเป็นเอนจินราคาทองคำทั้งหมด แต่ยังคงเป็นเพียงชั้นข้อมูลอัตราแลกเปลี่ยน การรักษาขอบเขตนี้ให้ชัดเจนช่วยป้องกันไม่ให้ความสดใหม่ของสกุลเงิน ความสดใหม่ของโลหะ และกฎการแปลงค่าเฉพาะผลิตภัณฑ์ ถูกรวมกันเป็นค่าเดียวที่กำกวม

  • goldprice.dev สามารถเปิดให้ใช้งานอินเทอร์เฟซขนาดเล็กเฉพาะโลหะ โดยไม่ต้องให้ผู้เรียกใช้งานประกอบเส้นทางทั่วไปด้วยตัวเอง
  • exchangerate.dev ยังคงรักษาสัญญาอัตราแลกเปลี่ยนทั่วไปที่มีประโยชน์นอกเหนือขอบเขตของโลหะ
  • ผู้ใช้งานที่ต้องการตรวจสอบย้อนกลับสามารถดึงและจัดเก็บค่าสังเกตทั้งสองแยกจากกันได้
  • แต่ละบริการสามารถรายงานความล้มเหลวและความสดใหม่ โดยใช้คำศัพท์เฉพาะของข้อมูลตลาดของตัวเอง

จัดการส่วนข้อมูลที่เก่าหรือขาดหายไปอย่างชัดเจน

ราคาที่รวมกันแล้วไม่ควรถูกนำไปใช้ต่อ หากข้อมูลนำเข้าฝั่งใดฝั่งหนึ่งขาดหายไป เป็นศูนย์ ไม่ใช่ตัวเลข หรืออยู่นอกช่วงความสดใหม่ที่ผลิตภัณฑ์ของคุณยอมรับ เก็บค่าที่ถูกต้องล่าสุดไว้ได้ก็ต่อเมื่ออินเทอร์เฟซระบุเวลาสังเกตดั้งเดิมกำกับไว้ด้วยเท่านั้น

  • ตรวจสอบการตอบกลับ HTTP ทั้งสองรายการก่อนทำการคำนวณ
  • ปฏิเสธราคาและอัตราที่ไม่ใช่จำนวนจำกัดหรือไม่เป็นบวก
  • กำหนดเกณฑ์ความสดใหม่แยกกันสำหรับทองคำและอัตราแลกเปลี่ยน
  • พิจารณา market_session: weekend เป็นเพียงบริบท ไม่ใช่หลักฐานว่าอัตราที่ยังคงค้างอยู่นั้นเป็นข้อมูลปัจจุบัน
  • บันทึกคู่สกุลเงินและเวลาสังเกตของข้อมูลต้นทางทั้งสองไว้พร้อมกับข้อผิดพลาดในการแปลงค่า

ปัดเศษเพื่อการแสดงผล ไม่ใช่ระหว่างการคำนวณ

รักษาความละเอียดเต็มรูปแบบตลอดการคูณ และปล่อยให้ locale ของการแสดงผลเป็นตัวกำหนดจำนวนตำแหน่งทศนิยมสุดท้าย Intl.NumberFormat จัดการสัญลักษณ์สกุลเงินและการจัดกลุ่มตัวเลขโดยไม่เปลี่ยนแปลงค่าที่แท้จริง:

javascript · locale-aware displaycopy
function formatPrice(amount, currency, locale) {
  return new Intl.NumberFormat(locale, {
    style: "currency",
    currency,
  }).format(amount);
}

console.log(formatPrice(result.prices.IDR, "IDR", "id-ID"));
console.log(formatPrice(result.prices.JPY, "JPY", "ja-JP"));

ใช้ผลลัพธ์เป็นมูลค่าเชิงบ่งชี้

มูลค่าตลาดที่คำนวณได้ไม่ใช่ราคาขายปลีกของเหรียญหรือทองคำแท่ง ค่าพรีเมียมจากผู้ค้า ภาษี ค่าผลิต ค่าธรรมเนียมการชำระเงิน และส่วนต่างอัตราแลกเปลี่ยนสำหรับการซื้อขายจริง ล้วนอยู่นอกเหนือสูตรนี้ ให้ระบุผลลัพธ์ว่าเป็นค่าเชิงบ่งชี้ เว้นแต่แอปพลิเคชันของคุณจะเพิ่มราคาจากผู้ค้าจริงพร้อมเงื่อนไขทางการค้าเข้าไปด้วย

สิ่งที่กรณีศึกษานี้พิสูจน์

goldprice.dev คือหลักฐานจากฝ่ายแรกที่แสดงว่า exchangerate.dev สามารถจัดหาส่วนของอัตราแลกเปลี่ยนให้กับเวิร์กโฟลว์การตั้งราคาในระบบใช้งานจริงได้ นี่ไม่ใช่หลักฐานทางสังคมที่เป็นอิสระ หลักฐานที่มีประโยชน์จริงนั้นแคบกว่าและทำซ้ำได้: นักพัฒนาสามารถเรียกใช้ผลิตภัณฑ์สาธารณะชุดเดียวกัน เก็บรักษาเวลาสังเกตทั้งสองไว้ และตรวจสอบการคำนวณด้วยตัวเองได้

MM
exchangerate.dev
บันทึกการผสานระบบใช้งานจริงสำหรับนักพัฒนา

Keep reading

Referenceการอ่านค่า source และ market_sessionRead Tutorialการแปลงสกุลเงินด้วย JavaScript และ Node.jsRead Guideอัตราแลกเปลี่ยนเชิงบ่งชี้ กับ อัตราสำหรับการซื้อขายจริงRead