@yusifaliyevpro/countries
Version:
TypeScript wrapper for Rest Countries API to fetch country data by codes, capitals, or all countries with full typings.
501 lines (500 loc) • 18.5 kB
JavaScript
//#region src/constants.ts
const API_BASE_URL = "https://restcountries.com/v3.1";
//#endregion
//#region src/helpers.ts
function constructAPI({ route = "all", query = "", fields, status, codes, fullText }) {
const base_url = new URL(API_BASE_URL);
if (status !== void 0) route = "independent";
base_url.pathname += `/${route}/${query.toLowerCase()}`;
if (status !== void 0) base_url.searchParams.set("status", String(status));
if (fullText !== void 0) base_url.searchParams.set("fullText", String(fullText));
if (codes) base_url.searchParams.append("codes", codes.toLowerCase());
fields = Array.from(new Set(fields));
if (fields && fields.length) base_url.searchParams.set("fields", fields.join(","));
return base_url;
}
function handleNotFoundError(ok) {
if (!ok) console.error("Couldn't find any country that matches your query, if you think it is issue please submit it via github issues");
}
function handleNetworkError(error) {
console.warn("A network or REST Countries API side error happened while fetching data. Try again later.");
console.warn("If this error persists, please verify the status of the REST Countries API. If the issue continues, feel free to report it on GitHub: https://github.com/yusifaliyevpro/countries");
console.error(error);
}
//#endregion
//#region src/functions/getCountries.ts
/**
* Fetches all countries, optionally filtered by independence status,
* and including only the specified fields.
*
* > **Note:** The `fields` parameter is required and you can only specify upto 10 fields,
* as mandated by Alejandro Matos See: {@link https://gitlab.com/restcountries/restcountries/-/issues/265}.
*
* @param params - An object containing:
* - `fields`: A required array of field names (keys from the `Country` type) to include in the response.
* - `independent`: If true, only includes independent countries; if false, only dependent ones.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or no countries match the criteria.
*
* @example
* // Get all countries with only the `name` and `area` fields
* const countries = await getCountries({ fields: ["name", "area"] });
*
* @example
* // Get all independent countries with only the `name` and `area` fields
* const independentCountries = await getCountries({
* independent: true,
* fields: ["name", "area"]
* });
*/
async function getCountries({ independent, fields }, fetchOptions) {
try {
if (fields.length > 10) console.error("You can specify up to 10 fields only");
const api = constructAPI({
status: independent,
fields
});
const response = await fetch(api.toString(), fetchOptions);
handleNotFoundError(response.ok);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesByCodes.ts
/**
* Fetches countries by their codes (e.g., CCA2, CCA3, or CIOC), optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
*
* @param params - An object containing:
* - `codes`: An array of country codes to fetch data for. CCA3 is recommended for precision.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or the countries are not found.
*
* @example
* // Get countries by CCA3 codes with only `name` and `flags` fields
* const countries = await getCountriesByCodes({
* codes: ["USA", "FRA", "JPN"],
* fields: ["name", "flags"]
* });
*
* @example
* // Get countries by CCA2 codes with all fields
* const countries = await getCountriesByCodes({ codes: ["US", "FR", "JP"] });
*/
async function getCountriesByCodes({ codes, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "alpha",
codes: codes.join(","),
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesByCurrency.ts
/**
* Fetches countries that use the specified currency, optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
*
* @param params - An object containing:
* - `currency`: The currency code (e.g., "USD", "EUR", "JPY") used to filter countries.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or no countries use the specified currency.
*
* @example
* // Get countries using the Euro with only `name` and `flags` fields
* const euroCountries = await getCountriesByCurrency({
* currency: "EUR",
* fields: ["name", "flags"]
* });
*
* @example
* // Get countries using the Japanese Yen with all fields
* const yenCountries = await getCountriesByCurrency({ currency: "JPY" });
*/
async function getCountriesByCurrency({ currency, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "currency",
query: currency,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesByLang.ts
/**
* Fetches countries where the specified language is officially or widely spoken,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
*
* @param params - An object containing:
* - `lang`: (e.g., "Spanish", "English", "Azerbaijani").
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or no countries match the language criteria.
*
* @example
* // Get countries where Spanish is spoken with `name` and `region` fields
* const spanishSpeakingCountries = await getCountriesByLang({
* lang: "spa",
* fields: ["name", "region"]
* });
*
* @example
* // Get countries where English is spoken with all fields
* const englishSpeakingCountries = await getCountriesByLang({ lang: "en" });
*/
async function getCountriesByLang({ lang, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "lang",
query: lang,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesByName.ts
/**
* Fetches countries that match a given name or partial name,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
* > Set `fullText` to `true` to require an exact, full-name match.
*
* @param params - An object containing:
* - `name`: The country name or partial name to search for (e.g., "united").
* - `fullText`: Optional boolean to indicate whether to match full names exactly.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or no countries match the name.
*
* @example
* // Search countries containing "united" with only `name` and `flags` fields
* const results = await getCountriesByName({
* name: "united",
* fields: ["name", "flags"]
* });
*
* @example
* // Search for exact match of "Finland" with all fields
* const country = await getCountriesByName({ name: "Finland", fullText: true });
*/
async function getCountriesByName({ name, fullText, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "name",
query: name,
fields,
fullText
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesByRegion.ts
/**
* Fetches countries which belong to the specified world region,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
*
* @param params - An object containing:
* - `region`: The name of the region (e.g., "Asia", "Europe", "Africa") to filter countries by.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or the region is not found.
*
* @example
* // Get Asian countries with only `name` and `population` fields
* const asianCountries = await getCountriesByRegion({
* region: "Asia",
* fields: ["name", "population"]
* });
*
* @example
* // Get all fields for countries in Europe
* const europeanCountries = await getCountriesByRegion({ region: "Europe" });
*/
async function getCountriesByRegion({ region, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "region",
query: region,
fields
});
const response = await fetch(api.toString(), fetchOptions);
handleNotFoundError(response.ok);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountriesBySubregion.ts
/**
* Fetches countries that belong to the specified subregion,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
*
* @param params - An object containing:
* - `subregion`: The subregion name (e.g., "Southern Asia", "Northern Europe") to filter countries by.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to an array of `CountryPicker<T>` objects with the requested fields,
* or `null` if the request fails or no countries match the subregion.
*
* @example
* // Get countries in Northern Europe with only `name` and `population` fields
* const nordicCountries = await getCountriesBySubregion({
* subregion: "Northern Europe",
* fields: ["name", "population"]
* });
*
* @example
* // Get all fields for countries in Southern Asia
* const southAsianCountries = await getCountriesBySubregion({ subregion: "Southern Asia" });
*/
async function getCountriesBySubregion({ subregion, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "subregion",
query: subregion,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? await response.json() : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountryByCapital.ts
/**
* Fetches a single country by its capital city,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
* > Returns the first matching country or `null` if none is found.
*
* @param params - An object containing:
* - `capital`: The name of the capital city to search for.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to a single `CountryPicker<T>` object with the requested fields,
* or `null` if the request fails or no country matches the capital city.
*
* @example
* // Get country by capital "Paris" with only `name` and `region` fields
* const country = await getCountryByCapital({
* capital: "Paris",
* fields: ["name", "region"]
* });
*
* @example
* // Get all fields for the country with capital "Tokyo"
* const japan = await getCountryByCapital({ capital: "Tokyo" });
*/
async function getCountryByCapital({ capital, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "capital",
query: capital,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? (await response.json())[0] : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountryByCode.ts
/**
* Fetches a single country by its code (e.g., CCA2, CCA3, or CIOC),
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
* > Returns the first matching country or `null` if none is found.
*
* @param params - An object containing:
* - `code`: The country code to fetch data for. CCA3 is recommended for precision.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to a single `CountryPicker<T>` object with the requested fields,
* or `null` if the request fails or no country matches the code.
*
* @example
* // Get country by CCA3 code "USA" with only `name` and `flags` fields
* const usa = await getCountryByCode({
* code: "USA",
* fields: ["name", "flags"]
* });
*
* @example
* // Get all fields for the country with code "FRA"
* const france = await getCountryByCode({ code: "FRA" });
*/
async function getCountryByCode({ code, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "alpha",
query: code,
fields
});
const response = await fetch(api.toString(), fetchOptions);
const data = await response.json();
return response.ok ? fields && !!fields.length ? data : data[0] : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountryByDemonym.ts
/**
* Fetches a single country by its demonym (the name for its residents),
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
* > Returns the first matching country or `null` if none is found.
*
* @param params - An object containing:
* - `demonym`: The demonym string to search for (e.g., "American", "French").
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to a single `CountryPicker<T>` object with the requested fields,
* or `null` if the request fails or no country matches the demonym.
*
* @example
* // Get country by demonym "Canadian" with only `name` and `region` fields
* const canada = await getCountryByDemonym({
* demonym: "Canadian",
* fields: ["name", "region"]
* });
*
* @example
* // Get all fields for the country with demonym "Brazilian"
* const brazil = await getCountryByDemonym({ demonym: "Brazilian" });
*/
async function getCountryByDemonym({ demonym, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "demonym",
query: demonym,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? (await response.json())[0] : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/functions/getCountryByTranslation.ts
/**
* Fetches a single country by a translated country name,
* optionally including only the specified fields.
*
* > **Note:** If `fields` is not provided, all available fields will be returned.
* > Returns the first matching country or `null` if none is found.
*
* @param params - An object containing:
* - `translation`: The translated name of the country to search for.
* - `fields`: An optional array of field names (keys from the `Country` type) to include in the response.
*
* @param fetchOptions - Optional `RequestInit` object to customize the `fetch` request.
*
* @returns A promise that resolves to a single `CountryPicker<T>` object with the requested fields,
* or `null` if the request fails or no country matches the translation.
*
* @example
* // Get country by translation "Alemania" (German for Germany) with only `name` and `region` fields
* const germany = await getCountryByTranslation({
* translation: "Alemania",
* fields: ["name", "region"]
* });
*
* @example
* // Get all fields for the country with translation "Espagne" (French for Spain)
* const spain = await getCountryByTranslation({ translation: "Espagne" });
*/
async function getCountryByTranslation({ translation, fields }, fetchOptions) {
try {
const api = constructAPI({
route: "translation",
query: translation,
fields
});
const response = await fetch(api.toString(), fetchOptions);
return response.ok ? (await response.json())[0] : null;
} catch (error) {
handleNetworkError(error);
return null;
}
}
//#endregion
//#region src/index.ts
const defineFields = (fields) => fields;
//#endregion
export { defineFields, getCountries, getCountriesByCodes, getCountriesByCurrency, getCountriesByLang, getCountriesByName, getCountriesByRegion, getCountriesBySubregion, getCountryByCapital, getCountryByCode, getCountryByDemonym, getCountryByTranslation };
//# sourceMappingURL=index.mjs.map