Node.js Examples
Server-side patterns using @koshmoney/countries with Node.js and Express.
Country Code Validation API
An Express endpoint that validates and normalizes country codes:
import express from 'express';
import { country } from '@koshmoney/countries';
const app = express();
app.use(express.json());
app.get('/api/country/:code', (req, res) => {
const info = country.whereAlpha2(req.params.code)
|| country.whereAlpha3(req.params.code);
if (!info) {
return res.status(404).json({ error: 'Country not found' });
}
res.json(info);
});
// Convert between formats
app.get('/api/country/convert', (req, res) => {
const { code, to } = req.query as { code: string; to: string };
if (!code || !to) {
return res.status(400).json({ error: 'Missing code or to parameter' });
}
const format = country.detectFormat(code);
if (!format) {
return res.status(400).json({ error: 'Invalid country code' });
}
if (format === 'name') {
const info = country.whereName(code);
return res.json({ result: info?.[to as keyof typeof info] || null });
}
const result = country.convert(code, format, to as any);
res.json({ from: format, to, result });
});Address Validation Endpoint
Validate a full address including country, state, and postal code:
import express from 'express';
import { country, subdivision, postalCode } from '@koshmoney/countries';
const app = express();
app.use(express.json());
app.post('/api/validate-address', (req, res) => {
const { countryCode, state, zip, city } = req.body;
const errors: string[] = [];
// Validate country
if (!countryCode || !country.isAlpha2(countryCode)) {
errors.push('Invalid or missing country code');
return res.status(400).json({ valid: false, errors });
}
// Validate state/province
if (state) {
if (!subdivision.isValidRegion(countryCode, state)) {
const subs = subdivision.forCountry(countryCode);
const type = subs[0]?.type || 'state/province';
errors.push(`Invalid ${type} "${state}" for ${country.toName(countryCode)}`);
}
}
// Validate postal code
if (zip) {
if (postalCode.hasPostalCode(countryCode) && !postalCode.isValid(countryCode, zip)) {
const name = postalCode.getName(countryCode) || 'Postal code';
const format = postalCode.getFormat(countryCode);
errors.push(`Invalid ${name}. Expected format: ${format}`);
}
}
if (errors.length > 0) {
return res.status(400).json({ valid: false, errors });
}
res.json({
valid: true,
normalized: {
country: country.toName(countryCode),
countryCode,
state: state ? subdivision.toNameFrom(countryCode, state) : null,
zip,
city,
},
});
});Subdivision List API
Serve subdivisions for a country (for dynamic dropdowns):
import express from 'express';
import { subdivision } from '@koshmoney/countries';
const app = express();
app.get('/api/subdivisions/:country', (req, res) => {
const subs = subdivision.forCountry(req.params.country);
if (subs.length === 0) {
return res.json({ subdivisions: [], type: null });
}
res.json({
type: subs[0].type, // "State", "Province", "Region", etc.
subdivisions: subs.map((s) => ({
code: s.regionCode,
name: s.name,
fullCode: s.code,
})),
});
});Shipping Rate Calculator
Use geography and membership data to calculate shipping zones:
import { country } from '@koshmoney/countries';
import { geography } from '@koshmoney/countries/geography';
import { membership } from '@koshmoney/countries/membership';
interface ShippingRate {
zone: string;
rate: number;
estimatedDays: string;
}
function getShippingRate(from: string, to: string): ShippingRate {
if (from === to) {
return { zone: 'Domestic', rate: 5.99, estimatedDays: '2-5' };
}
// EU to EU - free trade zone
if (membership.isEU(from) && membership.isEU(to)) {
return { zone: 'EU', rate: 9.99, estimatedDays: '3-7' };
}
// Same continent
const fromContinent = geography.getContinent(from);
const toContinent = geography.getContinent(to);
if (fromContinent && fromContinent === toContinent) {
return { zone: 'Regional', rate: 14.99, estimatedDays: '5-10' };
}
return { zone: 'International', rate: 24.99, estimatedDays: '7-21' };
}
// Usage in Express
app.get('/api/shipping-rate', (req, res) => {
const { from, to } = req.query as { from: string; to: string };
if (!country.isAlpha2(from) || !country.isAlpha2(to)) {
return res.status(400).json({ error: 'Invalid country codes' });
}
res.json(getShippingRate(from, to));
});Currency Formatting Helper
Format prices with the correct currency symbol:
import { currency } from '@koshmoney/countries/currency';
function formatPrice(amount: number, countryCode: string): string {
const curr = currency.getCurrency(countryCode);
if (!curr) return `${amount.toFixed(2)}`;
return `${curr.symbol}${amount.toFixed(2)} ${curr.code}`;
}
formatPrice(29.99, 'US'); // '$29.99 USD'
formatPrice(29.99, 'GB'); // '£29.99 GBP'
formatPrice(29.99, 'JP'); // '¥29.99 JPY'
formatPrice(29.99, 'IN'); // '₹29.99 INR'CLI Tool
A simple CLI that looks up country data:
import { country, subdivision } from '@koshmoney/countries';
import { currency } from '@koshmoney/countries/currency';
import { dialCode } from '@koshmoney/countries/dialCode';
const code = process.argv[2];
if (!code) {
console.log('Usage: npx tsx lookup.ts <country-code>');
process.exit(1);
}
const info = country.whereAlpha2(code)
|| country.whereAlpha3(code)
|| country.whereName(code);
if (!info) {
console.log(`Country not found: ${code}`);
process.exit(1);
}
const subs = subdivision.forCountry(info.alpha2);
const curr = currency.getCurrency(info.alpha2);
const dial = dialCode.getDialCode(info.alpha2);
console.log(`${info.name} (${info.alpha2} / ${info.alpha3} / ${info.numeric})`);
if (curr) console.log(` Currency: ${curr.symbol} ${curr.code} (${curr.name})`);
if (dial) console.log(` Dial code: ${dial}`);
console.log(` Subdivisions: ${subs.length}`);Related
- Address Validation Guide — Validation patterns
- React Examples — Frontend examples
- Country API — Full API reference