bgg-xml-api-client
Version:
A client for Boardgamegeek.com XML API (v1 and v2) that returns data as JS object.
209 lines (189 loc) • 7.02 kB
JavaScript
;
const ofetch = require('ofetch');
const fastXmlParser = require('fast-xml-parser');
function createResourceUrl(resource, queryParams) {
if (!resource)
throw new Error("You have to provide valid resource name!");
const isV1Api = /geeklist/i.test(resource);
if (isV1Api) {
const query = queryParams.comments ? `?comments=${queryParams.comments}` : "";
return `${resource}/${queryParams.id}${query}`;
}
return `${resource}${queryParams && Object.keys(queryParams).length ? `?${new URLSearchParams(queryParams)}` : ""}`;
}
const options = {
allowBooleanAttributes: true,
attributeNamePrefix: "",
ignoreAttributes: false,
ignoreDeclaration: true,
parseAttributeValue: true,
textNodeName: "text"
};
const parser = new fastXmlParser.XMLParser(options);
const xmlParser = {
parse: (xmlString) => parser.parse(xmlString)
};
const BGG_API_V1_BASE_URL = "https://boardgamegeek.com/xmlapi/";
const BGG_API_V2_BASE_URL = "https://boardgamegeek.com/xmlapi2/";
function getBaseUrlForResource(resource) {
if (!resource)
throw new Error("You have to provide valid resource name!");
return resource === "geeklist" ? BGG_API_V1_BASE_URL : BGG_API_V2_BASE_URL;
}
const DEFAULT_MAX_RETRIES = 10;
const DEFAULT_INTERVAL = 5e3;
const DEFAULT_TIMEOUT = 1e4;
const bggXmlApiClient = {
get: async (resource, queryParams, {
authorizationKey,
maxRetries = DEFAULT_MAX_RETRIES,
retryInterval = DEFAULT_INTERVAL,
timeout = DEFAULT_TIMEOUT
}) => {
if (!authorizationKey) {
throw new Error("authorizationKey is required to access BGG API as of fall 2025. See README for more details.");
}
const apiFetch = ofetch.ofetch.create({
baseURL: getBaseUrlForResource(resource),
headers: {
"Content-Type": "text/xml",
"Authorization": `Bearer ${authorizationKey}`
},
responseType: "text",
onResponse(context) {
if (context.response.status === 202)
throw new Error("processing...");
}
});
for (let i = 0; i < maxRetries; i++) {
try {
const resourceUrl = createResourceUrl(resource, queryParams);
const response = await apiFetch(resourceUrl, { timeout });
const parsedResponse = xmlParser.parse(response);
return parsedResponse[Object.keys(parsedResponse).shift()];
} catch (err) {
if (err instanceof Error && err.message === "processing...")
await new Promise((resolve) => setTimeout(() => resolve(), retryInterval));
else
throw err;
}
}
throw new Error(`Max retries reached! Resource: ${resource}, Params: ${JSON.stringify(queryParams)}`);
}
};
const bggXmlApiClient$1 = bggXmlApiClient;
function getBggCollection(params, settings) {
const newParams = {
...params,
...params.id && {
id: Array.isArray(params.id) ? params.id.join(",") : params.id
}
};
return bggXmlApiClient.get("collection", newParams, settings);
}
function getBggFamily(params, settings) {
const newParams = {
...params,
...params.id && { id: Array.isArray(params.id) ? params.id.join(",") : params.id }
};
return bggXmlApiClient.get("family", newParams, settings);
}
function getBggForum(params, settings) {
return bggXmlApiClient.get("forum", params, settings);
}
function getBggForumlist(params, settings) {
return bggXmlApiClient.get("forumlist", params, settings);
}
function getBggGeeklist(params, settings) {
return bggXmlApiClient$1.get("geeklist", params, settings);
}
function getBggGuild(params, settings) {
return bggXmlApiClient.get("guild", params, settings);
}
function getBggHot(params, settings) {
return bggXmlApiClient.get("hot", params, settings);
}
function getBggPlays(params, settings) {
if (!params.username && !(params.id && params.type))
throw new Error("You must specify either username or id and type");
return bggXmlApiClient.get("plays", params, settings);
}
function getBggSearch(params, settings) {
const newParams = {
...params,
...params.type && { type: Array.isArray(params.type) ? params.type.join(",") : params.type }
};
return bggXmlApiClient.get("search", newParams, settings);
}
function getBggThing(params, settings) {
const newParams = {
...params,
...params.id && { id: Array.isArray(params.id) ? params.id.join(",") : params.id },
...params.type && { type: Array.isArray(params.type) ? params.type.join(",") : params.type }
};
return bggXmlApiClient.get("thing", newParams, settings);
}
function getBggThread(params, settings) {
return bggXmlApiClient.get("thread", params, settings);
}
function getBggUser(params, settings) {
return bggXmlApiClient$1.get("user", params, settings);
}
class BggXmlApiClient {
constructor(bggApiToken) {
this.bggApiToken = bggApiToken;
}
get(resource, queryParams, settings) {
return bggXmlApiClient.get(resource, queryParams, { authorizationKey: this.bggApiToken, ...settings });
}
getBggCollection(params, settings) {
return getBggCollection(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggFamily(params, settings) {
return getBggFamily(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggForum(params, settings) {
return getBggForum(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggForumlist(params, settings) {
return getBggForumlist(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggGeeklist(params, settings) {
return getBggGeeklist(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggGuild(params, settings) {
return getBggGuild(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggHot(params, settings) {
return getBggHot(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggPlays(params, settings) {
return getBggPlays(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggSearch(params, settings) {
return getBggSearch(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggThing(params, settings) {
return getBggThing(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggThread(params, settings) {
return getBggThread(params, { authorizationKey: this.bggApiToken, ...settings });
}
getBggUser(params, settings) {
return getBggUser(params, { authorizationKey: this.bggApiToken, ...settings });
}
}
exports.BggXmlApiClient = BggXmlApiClient;
exports.bggXmlApiClient = bggXmlApiClient;
exports.getBggCollection = getBggCollection;
exports.getBggFamily = getBggFamily;
exports.getBggForum = getBggForum;
exports.getBggForumlist = getBggForumlist;
exports.getBggGeeklist = getBggGeeklist;
exports.getBggGuild = getBggGuild;
exports.getBggHot = getBggHot;
exports.getBggPlays = getBggPlays;
exports.getBggSearch = getBggSearch;
exports.getBggThing = getBggThing;
exports.getBggThread = getBggThread;
exports.getBggUser = getBggUser;