From 8a9672e2bffd6eef3fd216d5e39679037f80e5f7 Mon Sep 17 00:00:00 2001 From: Marcin Kurkiewicz Date: Tue, 5 Dec 2023 02:23:15 -0800 Subject: [PATCH] feat: add client options to control retries and timeout (#21) --- README.md | 32 +++++++++++++++- package.json | 2 +- pnpm-lock.yaml | 42 +++++++++++++++------ src/client/getBggApiClient.ts | 33 ---------------- src/client/index.ts | 42 +++++++++++++++------ src/helpers/xmlParser.ts | 2 +- src/types.ts | 8 +++- src/wrappers/getBggCollection.ts | 5 ++- src/wrappers/getBggFamily.ts | 6 +-- src/wrappers/getBggForum.ts | 5 ++- src/wrappers/getBggForumlist.ts | 5 ++- src/wrappers/getBggGeeklist.ts | 6 +-- src/wrappers/getBggGuild.ts | 6 +-- src/wrappers/getBggHot.ts | 6 +-- src/wrappers/getBggPlays.ts | 6 +-- src/wrappers/getBggSearch.ts | 6 +-- src/wrappers/getBggThing.ts | 6 +-- src/wrappers/getBggThread.ts | 5 ++- src/wrappers/getBggUser.ts | 6 +-- test/unit/client/getBggApiClient.spec.ts | 8 ---- test/unit/wrappers/getBggCollection.spec.ts | 8 ++-- test/unit/wrappers/getBggFamily.spec.ts | 4 +- test/unit/wrappers/getBggForum.spec.ts | 2 +- test/unit/wrappers/getBggForumlist.spec.ts | 2 +- test/unit/wrappers/getBggGeeklist.spec.ts | 2 +- test/unit/wrappers/getBggGuild.spec.ts | 2 +- test/unit/wrappers/getBggHot.spec.ts | 2 +- test/unit/wrappers/getBggPlays.spec.ts | 2 +- test/unit/wrappers/getBggSearch.spec.ts | 6 +-- test/unit/wrappers/getBggThing.spec.ts | 8 ++-- test/unit/wrappers/getBggThread.spec.ts | 2 +- test/unit/wrappers/getBggUser.spec.ts | 2 +- 32 files changed, 158 insertions(+), 121 deletions(-) delete mode 100644 src/client/getBggApiClient.ts delete mode 100644 test/unit/client/getBggApiClient.spec.ts diff --git a/README.md b/README.md index 560b92e..dfa3b22 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It uses [ofetch](https://github.com/unjs/ofetch) under the hood. ## Example usage: ```js -import bggXmlApiClient from 'bgg-xml-api-client' +import { bggXmlApiClient } from 'bgg-xml-api-client' const response = await bggXmlApiClient.get('user', { name: 'Qrzy88' }) @@ -33,3 +33,33 @@ There are also wrappers available for certain resources that accept params (alre - `getBggThing(params)` - `getBggThread(params)` - `getBggUser(params)` + +## Client options + +Both main client as well as wrappers accept one more parameter that can override default options: + +```js +interface ClientOptions { + maxRetries: number // default 10 + retryInterval: number // default 5000[ms] (5s) + timeout: number // default 10000[ms] (10s) +} +``` + +One can use it to control the retry flow when collections API replies with 202 status code meaning the request is still processing and one should retry later for actual results. + +For example, in order to increase number of retries on 202 response to 20 made in an interval of 3s: + +```js +import { bggXmlApiClient } from 'bgg-xml-api-client' + +const response = await bggXmlApiClient.get('collection', { username: 'Qrzy88' }, { maxRetries: 20, retryInterval: 3000 }) +``` + +or to reduce the timeout to 5s when fetching user: + +```js +import { getBggUser } from 'bgg-xml-api-client' + +const response = await getBggUser({ name: 'Qrzy88' }, { timeout: 5000 }) +``` diff --git a/package.json b/package.json index c694b4a..6d7d5b5 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ }, "dependencies": { "fast-xml-parser": "^4.2.4", - "ofetch": "^1.1.0" + "ofetch": "^1.3.3" }, "devDependencies": { "@antfu/eslint-config": "^0.39.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 23b19d3..d606574 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: true @@ -9,8 +9,8 @@ dependencies: specifier: ^4.2.4 version: 4.2.4 ofetch: - specifier: ^1.1.0 - version: 1.1.0 + specifier: ^1.3.3 + version: 1.3.3 devDependencies: '@antfu/eslint-config': @@ -295,6 +295,7 @@ packages: /@babel/highlight@7.22.5: resolution: {integrity: sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==} engines: {node: '>=6.9.0'} + requiresBuild: true dependencies: '@babel/helper-validator-identifier': 7.22.5 chalk: 2.4.2 @@ -1178,6 +1179,7 @@ packages: /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} + requiresBuild: true dependencies: color-convert: 1.9.3 dev: true @@ -1401,6 +1403,7 @@ packages: /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} + requiresBuild: true dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 @@ -1498,6 +1501,7 @@ packages: /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + requiresBuild: true dependencies: color-name: 1.1.3 dev: true @@ -1511,6 +1515,7 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + requiresBuild: true dev: true /color-name@1.1.4: @@ -1629,14 +1634,14 @@ packages: resolution: {integrity: sha512-+uO4+qr7msjNNWKYPHqN/3+Dx3NFkmIzayk2L1MyZQlvgZb/J1A0fo410dpKrN2SnqFjt8n4JL8fDJE0wIgjFQ==} dev: true - /destr@1.2.2: - resolution: {integrity: sha512-lrbCJwD9saUQrqUfXvl6qoM+QN3W7tLV5pAOs+OqOmopCCz/JkE05MHedJR1xfk4IAnZuJXPVuN5+7jNA2ZCiA==} - dev: false - /destr@2.0.0: resolution: {integrity: sha512-FJ9RDpf3GicEBvzI3jxc2XhHzbqD8p4ANw/1kPsFBfTvP1b7Gn/Lg1vO7R9J4IVgoMbyUmFrFGZafJ1hPZpvlg==} dev: true + /destr@2.0.2: + resolution: {integrity: sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==} + dev: false + /dir-glob@3.0.1: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} @@ -2519,6 +2524,7 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} + requiresBuild: true dev: true /has-flag@4.0.0: @@ -2834,6 +2840,7 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + requiresBuild: true dev: true /js-yaml@4.1.0: @@ -3214,6 +3221,11 @@ packages: /node-fetch-native@1.2.0: resolution: {integrity: sha512-5IAMBTl9p6PaAjYCnMv5FmqIF6GcZnawAVnzaCG0rX2aYZJ4CxEkZNtVPuTRug7fL7wyM5BQYTlAzcyMPi6oTQ==} + dev: true + + /node-fetch-native@1.4.1: + resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==} + dev: false /node-releases@2.0.12: resolution: {integrity: sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==} @@ -3274,12 +3286,12 @@ packages: es-abstract: 1.21.2 dev: true - /ofetch@1.1.0: - resolution: {integrity: sha512-yjq2ZUUMto1ITpge2J5vNlUfteLzxfHn9aJC55WtVGD3okKwSfPoLaKpcHXmmKd2kZZUGo+jdkFuuj09Blyeig==} + /ofetch@1.3.3: + resolution: {integrity: sha512-s1ZCMmQWXy4b5K/TW9i/DtiN8Ku+xCiHcjQ6/J/nDdssirrQNOoB165Zu8EqLMA2lln1JUth9a0aW9Ap2ctrUg==} dependencies: - destr: 1.2.2 - node-fetch-native: 1.2.0 - ufo: 1.1.2 + destr: 2.0.2 + node-fetch-native: 1.4.1 + ufo: 1.3.2 dev: false /ohash@1.1.2: @@ -3887,6 +3899,7 @@ packages: /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} + requiresBuild: true dependencies: has-flag: 3.0.0 dev: true @@ -4035,6 +4048,11 @@ packages: /ufo@1.1.2: resolution: {integrity: sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==} + dev: true + + /ufo@1.3.2: + resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} + dev: false /unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} diff --git a/src/client/getBggApiClient.ts b/src/client/getBggApiClient.ts deleted file mode 100644 index 6d78a13..0000000 --- a/src/client/getBggApiClient.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { FetchContext, FetchOptions, FetchResponse } from 'ofetch' -import { ofetch } from 'ofetch' -import { getBaseUrlForResource } from '../helpers/getBaseUrlForResource' -import { xmlParser } from '../helpers/xmlParser' -import type { ResourceName } from '../types' - -const DEFAULT_TIMEOUT = 10000 // milliseconds - -export function getBggApiClient(resource: ResourceName, timeout?: number) { - const controller = new AbortController() - const apiFetch = ofetch.create({ - baseURL: getBaseUrlForResource(resource), - headers: { - 'Content-Type': 'text/xml', - }, - responseType: 'text', - signal: controller.signal, - async onResponse({ response }: FetchContext & { response: FetchResponse<'text'> }) { - // get rid of the very root element of the response - const parsedResponse: any = await xmlParser.parse(response._data) - response._data = parsedResponse[Object.keys(parsedResponse).shift()!] - }, - }) - - return { - async get(url: string, options?: FetchOptions<'json'>) { - const timeoutId = setTimeout(() => controller.abort(), timeout || DEFAULT_TIMEOUT) - const response = await apiFetch(url, options) - clearTimeout(timeoutId) - return response - }, - } -} diff --git a/src/client/index.ts b/src/client/index.ts index 18eeab3..47e4a2a 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,30 +1,50 @@ /* istanbul ignore file */ +import { ofetch } from 'ofetch' import { createResourceUrl } from '../helpers/createResourceUrl' -import type { BggParams, ResourceName } from '../types' -import { getBggApiClient } from './getBggApiClient' +import type { BggParams, ClientOptions, ResourceName } from '../types' +import { xmlParser } from '../helpers/xmlParser' +import { getBaseUrlForResource } from '../helpers/getBaseUrlForResource' export const DEFAULT_MAX_RETRIES = 10 export const DEFAULT_INTERVAL = 5000 +export const DEFAULT_TIMEOUT = 10000 // milliseconds export const bggXmlApiClient = { get: async ( resource: ResourceName, queryParams: BggParams, - maxRetries: number = DEFAULT_MAX_RETRIES, - retryInterval: number = DEFAULT_INTERVAL, + { + maxRetries = DEFAULT_MAX_RETRIES, + retryInterval = DEFAULT_INTERVAL, + timeout = DEFAULT_TIMEOUT, + }: Partial = {}, ): Promise => { - const client = getBggApiClient(resource) + const apiFetch = ofetch.create({ + baseURL: getBaseUrlForResource(resource), + headers: { + 'Content-Type': 'text/xml', + }, + 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 client.get(resourceUrl) - if (typeof response === 'string' && (response as string).includes('processed')) - throw new Error('processing...') - - return response + const response = await apiFetch(resourceUrl, { timeout }) + const parsedResponse = xmlParser.parse<{ [key: string]: T }>(response) + return parsedResponse[Object.keys(parsedResponse).shift()!] } catch (err) { - await new Promise(resolve => setTimeout(() => resolve(), retryInterval)) + if (err instanceof Error && err.message === 'processing...') + // BGG API is still processing the request, retry after a while + await new Promise(resolve => setTimeout(() => resolve(), retryInterval)) + else + // an actual error occurred, throw it + throw err } } diff --git a/src/helpers/xmlParser.ts b/src/helpers/xmlParser.ts index 42bbc09..a4d55b7 100644 --- a/src/helpers/xmlParser.ts +++ b/src/helpers/xmlParser.ts @@ -14,5 +14,5 @@ const options: Partial = { const parser = new XMLParser(options) export const xmlParser: XmlParser = { - parse: (xmlString: XmlString) => parser.parse(xmlString), + parse: (xmlString: XmlString): T => parser.parse(xmlString), } diff --git a/src/types.ts b/src/types.ts index babdb90..4d37b6a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -29,6 +29,12 @@ export type ResourceName = | 'hot' | 'search' +export interface ClientOptions { + maxRetries: number + retryInterval: number + timeout: number +} + export type OneOrNothing = 1 | undefined export type SingleOrMany = T | T[] @@ -64,5 +70,5 @@ export type BggParams = export type XmlString = string export interface XmlParser { - parse: (text: XmlString) => unknown + parse: (text: XmlString) => T } diff --git a/src/wrappers/getBggCollection.ts b/src/wrappers/getBggCollection.ts index c7bd2e5..21d8d41 100644 --- a/src/wrappers/getBggCollection.ts +++ b/src/wrappers/getBggCollection.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OfValue, OneOrNothing } from '../types' +import type { ClientOptions, OfValue, OneOrNothing } from '../types' type BggCollectionSubtype = | 'boardgame' @@ -135,6 +135,7 @@ export interface BggCollectionResponse { export function getBggCollection( params: BggCollectionParams, + settings: Partial = {}, ): Promise { const newParams = { ...params, @@ -142,5 +143,5 @@ export function getBggCollection( id: Array.isArray(params.id) ? params.id.join(',') : params.id, }), } - return bggXmlApiClient.get('collection', newParams) + return bggXmlApiClient.get('collection', newParams, settings) } diff --git a/src/wrappers/getBggFamily.ts b/src/wrappers/getBggFamily.ts index 8a9481b..d4c7476 100644 --- a/src/wrappers/getBggFamily.ts +++ b/src/wrappers/getBggFamily.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { BggFamilyType, SingleOrMany } from '../types' +import type { BggFamilyType, ClientOptions, SingleOrMany } from '../types' export interface BggFamilyParams { id?: number | number[] | string @@ -31,10 +31,10 @@ export interface BggFamilyResponse { [prop: string]: unknown } -export function getBggFamily(params: BggFamilyParams): Promise { +export function getBggFamily(params: BggFamilyParams, settings: Partial = {}): Promise { const newParams = { ...params, ...(params.id && { id: Array.isArray(params.id) ? params.id.join(',') : params.id }), } - return bggXmlApiClient.get('family', newParams) + return bggXmlApiClient.get('family', newParams, settings) } diff --git a/src/wrappers/getBggForum.ts b/src/wrappers/getBggForum.ts index eb75361..fc94b08 100644 --- a/src/wrappers/getBggForum.ts +++ b/src/wrappers/getBggForum.ts @@ -1,4 +1,5 @@ import { bggXmlApiClient } from '../client' +import type { ClientOptions } from '../types' export interface BggForumParams { id?: number @@ -28,6 +29,6 @@ export interface BggForumResponse { [prop: string]: unknown } -export function getBggForum(params: BggForumParams): Promise { - return bggXmlApiClient.get('forum', params) +export function getBggForum(params: BggForumParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('forum', params, settings) } diff --git a/src/wrappers/getBggForumlist.ts b/src/wrappers/getBggForumlist.ts index 2882de3..bfe9951 100644 --- a/src/wrappers/getBggForumlist.ts +++ b/src/wrappers/getBggForumlist.ts @@ -2,6 +2,7 @@ // TODO: get known what is it and test properly! import { bggXmlApiClient } from '../client' +import type { ClientOptions } from '../types' export interface BggForumlistParams { id?: number @@ -13,6 +14,6 @@ export interface BggForumlistResponse { [prop: string]: unknown } -export function getBggForumlist(params: BggForumlistParams): Promise { - return bggXmlApiClient.get('forumlist', params) +export function getBggForumlist(params: BggForumlistParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('forumlist', params, settings) } diff --git a/src/wrappers/getBggGeeklist.ts b/src/wrappers/getBggGeeklist.ts index dfa39f2..b08948b 100644 --- a/src/wrappers/getBggGeeklist.ts +++ b/src/wrappers/getBggGeeklist.ts @@ -1,5 +1,5 @@ import bggXmlApiClient from '../client' -import type { OneOrNothing } from '../types' +import type { ClientOptions, OneOrNothing } from '../types' export interface GeeklistParams { id: number @@ -46,6 +46,6 @@ export interface GeeklistResponse { [prop: string]: unknown } -export function getBggGeeklist(params: GeeklistParams): Promise { - return bggXmlApiClient.get('geeklist', params) +export function getBggGeeklist(params: GeeklistParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('geeklist', params, settings) } diff --git a/src/wrappers/getBggGuild.ts b/src/wrappers/getBggGuild.ts index 8a66b01..84ece42 100644 --- a/src/wrappers/getBggGuild.ts +++ b/src/wrappers/getBggGuild.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OneOrNothing } from '../types' +import type { ClientOptions, OneOrNothing } from '../types' export interface BggGuildParams { id?: number @@ -38,6 +38,6 @@ export interface BggGuildResponse { [prop: string]: unknown } -export function getBggGuild(params: BggGuildParams): Promise { - return bggXmlApiClient.get('guild', params) +export function getBggGuild(params: BggGuildParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('guild', params, settings) } diff --git a/src/wrappers/getBggHot.ts b/src/wrappers/getBggHot.ts index 6709536..4af4282 100644 --- a/src/wrappers/getBggHot.ts +++ b/src/wrappers/getBggHot.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OfValue } from '../types' +import type { ClientOptions, OfValue } from '../types' export interface BggHotParams { type: @@ -26,6 +26,6 @@ export interface BggHotResponse { [prop: string]: unknown } -export function getBggHot(params: BggHotParams): Promise { - return bggXmlApiClient.get('hot', params) +export function getBggHot(params: BggHotParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('hot', params, settings) } diff --git a/src/wrappers/getBggPlays.ts b/src/wrappers/getBggPlays.ts index 13526b8..c40e279 100644 --- a/src/wrappers/getBggPlays.ts +++ b/src/wrappers/getBggPlays.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OfValue } from '../types' +import type { ClientOptions, OfValue } from '../types' export interface BggPlaysParams { username?: string @@ -39,9 +39,9 @@ export interface BggPlaysResponse { [prop: string]: unknown } -export function getBggPlays(params: BggPlaysParams): Promise { +export function getBggPlays(params: BggPlaysParams, settings: Partial = {}): Promise { if (!params.username && !(params.id && params.type)) throw new Error('You must specify either username or id and type') - return bggXmlApiClient.get('plays', params) + return bggXmlApiClient.get('plays', params, settings) } diff --git a/src/wrappers/getBggSearch.ts b/src/wrappers/getBggSearch.ts index e26533e..26d2da0 100644 --- a/src/wrappers/getBggSearch.ts +++ b/src/wrappers/getBggSearch.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OfValue, OneOrNothing } from '../types' +import type { ClientOptions, OfValue, OneOrNothing } from '../types' export type SearchType = 'rpgitem' | 'videogame' | 'boardgame' | 'boardgameaccessory' | 'boardgameexpansion' @@ -25,10 +25,10 @@ export interface BggSearchResponse { [prop: string]: unknown } -export function getBggSearch(params: BggSearchParams): Promise { +export function getBggSearch(params: BggSearchParams, settings: Partial = {}): Promise { const newParams = { ...params, ...(params.type && { type: Array.isArray(params.type) ? params.type.join(',') : params.type }), } - return bggXmlApiClient.get('search', newParams) + return bggXmlApiClient.get('search', newParams, settings) } diff --git a/src/wrappers/getBggThing.ts b/src/wrappers/getBggThing.ts index c6635ef..160c42a 100644 --- a/src/wrappers/getBggThing.ts +++ b/src/wrappers/getBggThing.ts @@ -1,5 +1,5 @@ import { bggXmlApiClient } from '../client' -import type { OfValue, OneOrNothing, SingleOrMany, ThingType } from '../types' +import type { ClientOptions, OfValue, OneOrNothing, SingleOrMany, ThingType } from '../types' export interface BggThingParams { id?: number | number[] | string @@ -267,11 +267,11 @@ export interface BggThingResponse { [prop: string]: unknown } -export function getBggThing(params: BggThingParams): Promise { +export function getBggThing(params: BggThingParams, settings: Partial = {}): Promise { 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) + return bggXmlApiClient.get('thing', newParams, settings) } diff --git a/src/wrappers/getBggThread.ts b/src/wrappers/getBggThread.ts index bbb7f8b..a4381a2 100644 --- a/src/wrappers/getBggThread.ts +++ b/src/wrappers/getBggThread.ts @@ -1,4 +1,5 @@ import { bggXmlApiClient } from '../client' +import type { ClientOptions } from '../types' export interface BggThreadParams { id?: number @@ -14,6 +15,6 @@ export interface BggThreadResponse { [prop: string]: unknown } -export function getBggThread(params: BggThreadParams): Promise { - return bggXmlApiClient.get('thread', params) +export function getBggThread(params: BggThreadParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('thread', params, settings) } diff --git a/src/wrappers/getBggUser.ts b/src/wrappers/getBggUser.ts index 3f96d9b..31d63dd 100644 --- a/src/wrappers/getBggUser.ts +++ b/src/wrappers/getBggUser.ts @@ -1,5 +1,5 @@ import bggXmlApiClient from '../client' -import type { OfValue, OneOrNothing } from '../types' +import type { ClientOptions, OfValue, OneOrNothing } from '../types' export interface BggUserParams { name?: string @@ -49,6 +49,6 @@ export interface BggUserResponse { [key: string]: any } -export function getBggUser(params: BggUserParams): Promise { - return bggXmlApiClient.get('user', params) +export function getBggUser(params: BggUserParams, settings: Partial = {}): Promise { + return bggXmlApiClient.get('user', params, settings) } diff --git a/test/unit/client/getBggApiClient.spec.ts b/test/unit/client/getBggApiClient.spec.ts deleted file mode 100644 index 6e89447..0000000 --- a/test/unit/client/getBggApiClient.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getBggApiClient } from '../../../src/client/getBggApiClient' - -describe('getBggApiClient', () => { - it('throws when empty resource given', () => { - expect(() => getBggApiClient('' as never)).toThrow() - }) -}) diff --git a/test/unit/wrappers/getBggCollection.spec.ts b/test/unit/wrappers/getBggCollection.spec.ts index 84d80e7..654db8d 100644 --- a/test/unit/wrappers/getBggCollection.spec.ts +++ b/test/unit/wrappers/getBggCollection.spec.ts @@ -1,22 +1,22 @@ import { describe, expect, it, vi } from 'vitest' import { getBggCollection } from '../../../src/wrappers' -import bggXmlApiClient from '../../../src/client' +import { bggXmlApiClient } from '../../../src/client' vi.mock('../../../src/client') describe('getBggCollection', () => { it('passes given username', async () => { await getBggCollection({ username: 'user' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user' }, {}) }) it('passes given ID', async () => { await getBggCollection({ username: 'user', id: 123 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user', id: 123 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user', id: 123 }, {}) }) it('passes given array of IDs', async () => { await getBggCollection({ username: 'user', id: [123, 456, 789] }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user', id: '123,456,789' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('collection', { username: 'user', id: '123,456,789' }, {}) }) }) diff --git a/test/unit/wrappers/getBggFamily.spec.ts b/test/unit/wrappers/getBggFamily.spec.ts index 284c1fb..e5c05aa 100644 --- a/test/unit/wrappers/getBggFamily.spec.ts +++ b/test/unit/wrappers/getBggFamily.spec.ts @@ -7,11 +7,11 @@ vi.mock('../../../src/client') describe('getBggFamily', () => { it('gets family with given ID', async () => { await getBggFamily({ id: 12210 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('family', { id: 12210 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('family', { id: 12210 }, {}) }) it('gets family with list of IDs', async () => { await getBggFamily({ id: [12210, 17552] }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('family', { id: '12210,17552' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('family', { id: '12210,17552' }, {}) }) }) diff --git a/test/unit/wrappers/getBggForum.spec.ts b/test/unit/wrappers/getBggForum.spec.ts index feb34ea..27bd741 100644 --- a/test/unit/wrappers/getBggForum.spec.ts +++ b/test/unit/wrappers/getBggForum.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggForum', () => { it('gets forum with given ID', async () => { await getBggForum({ id: 19 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('forum', { id: 19 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('forum', { id: 19 }, {}) }) }) diff --git a/test/unit/wrappers/getBggForumlist.spec.ts b/test/unit/wrappers/getBggForumlist.spec.ts index 33bf323..6b4ba97 100644 --- a/test/unit/wrappers/getBggForumlist.spec.ts +++ b/test/unit/wrappers/getBggForumlist.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggForumlist', () => { it('gets forumlist with given ID', async () => { await getBggForumlist({ id: 13, type: 'thing' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('forumlist', { id: 13, type: 'thing' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('forumlist', { id: 13, type: 'thing' }, {}) }) }) diff --git a/test/unit/wrappers/getBggGeeklist.spec.ts b/test/unit/wrappers/getBggGeeklist.spec.ts index deafa84..a621314 100644 --- a/test/unit/wrappers/getBggGeeklist.spec.ts +++ b/test/unit/wrappers/getBggGeeklist.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggGeeklist', () => { it('gets geeklist with given ID', async () => { await getBggGeeklist({ id: 272940, comments: 1 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('geeklist', { id: 272940, comments: 1 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('geeklist', { id: 272940, comments: 1 }, {}) }) }) diff --git a/test/unit/wrappers/getBggGuild.spec.ts b/test/unit/wrappers/getBggGuild.spec.ts index ab8a283..e11c622 100644 --- a/test/unit/wrappers/getBggGuild.spec.ts +++ b/test/unit/wrappers/getBggGuild.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggGuild', () => { it('gets guild with given ID', async () => { await getBggGuild({ id: 1497 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('guild', { id: 1497 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('guild', { id: 1497 }, {}) }) }) diff --git a/test/unit/wrappers/getBggHot.spec.ts b/test/unit/wrappers/getBggHot.spec.ts index f8a2b36..d18458b 100644 --- a/test/unit/wrappers/getBggHot.spec.ts +++ b/test/unit/wrappers/getBggHot.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggHot', () => { it('gets hot', async () => { await getBggHot({ type: 'boardgame' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('hot', { type: 'boardgame' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('hot', { type: 'boardgame' }, {}) }) }) diff --git a/test/unit/wrappers/getBggPlays.spec.ts b/test/unit/wrappers/getBggPlays.spec.ts index 73df85c..a728947 100644 --- a/test/unit/wrappers/getBggPlays.spec.ts +++ b/test/unit/wrappers/getBggPlays.spec.ts @@ -7,7 +7,7 @@ vi.mock('../../../src/client') describe('getBggPlays', () => { it('gets plays with given username', async () => { await getBggPlays({ username: 'Qrzy88' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('plays', { username: 'Qrzy88' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('plays', { username: 'Qrzy88' }, {}) }) it('throws when necessary params are not given', async () => { diff --git a/test/unit/wrappers/getBggSearch.spec.ts b/test/unit/wrappers/getBggSearch.spec.ts index 72f35fd..520812a 100644 --- a/test/unit/wrappers/getBggSearch.spec.ts +++ b/test/unit/wrappers/getBggSearch.spec.ts @@ -7,12 +7,12 @@ vi.mock('../../../src/client') describe('getBggSearch', () => { it('gets search with given term', async () => { await getBggSearch({ query: 'alhambra' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('search', { query: 'alhambra' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('search', { query: 'alhambra' }, {}) }) it('gets search with given term and type', async () => { await getBggSearch({ query: 'alhambra', type: 'boardgame' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('search', { query: 'alhambra', type: 'boardgame' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('search', { query: 'alhambra', type: 'boardgame' }, {}) }) it('gets search with given term and types list', async () => { @@ -20,6 +20,6 @@ describe('getBggSearch', () => { expect(bggXmlApiClient.get).toHaveBeenCalledWith('search', { query: 'alhambra', type: 'boardgame,boardgameexpansion', - }) + }, {}) }) }) diff --git a/test/unit/wrappers/getBggThing.spec.ts b/test/unit/wrappers/getBggThing.spec.ts index 8a558cf..acb09e4 100644 --- a/test/unit/wrappers/getBggThing.spec.ts +++ b/test/unit/wrappers/getBggThing.spec.ts @@ -7,17 +7,17 @@ vi.mock('../../../src/client') describe('getBggThing', () => { it('gets thing with given ID', async () => { await getBggThing({ id: 6249 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: 6249 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: 6249 }, {}) }) it('gets thing with list of IDs', async () => { await getBggThing({ id: [6249, 202976] }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: '6249,202976' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: '6249,202976' }, {}) }) it('gets thing with given ID and type', async () => { await getBggThing({ id: 6249, type: 'boardgame' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: 6249, type: 'boardgame' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: 6249, type: 'boardgame' }, {}) }) it('gets thing with list of IDs and types', async () => { @@ -25,6 +25,6 @@ describe('getBggThing', () => { expect(bggXmlApiClient.get).toHaveBeenCalledWith('thing', { id: '6249,202976', type: 'boardgame,boardgameexpansion', - }) + }, {}) }) }) diff --git a/test/unit/wrappers/getBggThread.spec.ts b/test/unit/wrappers/getBggThread.spec.ts index a8a3e4b..b6385cc 100644 --- a/test/unit/wrappers/getBggThread.spec.ts +++ b/test/unit/wrappers/getBggThread.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggThread', () => { it('gets thread with given ID', async () => { await getBggThread({ id: 2427564 }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('thread', { id: 2427564 }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('thread', { id: 2427564 }, {}) }) }) diff --git a/test/unit/wrappers/getBggUser.spec.ts b/test/unit/wrappers/getBggUser.spec.ts index 2528c71..da35e17 100644 --- a/test/unit/wrappers/getBggUser.spec.ts +++ b/test/unit/wrappers/getBggUser.spec.ts @@ -7,6 +7,6 @@ vi.mock('../../../src/client') describe('getBggUser', () => { it('gets user with given name', async () => { await getBggUser({ name: 'Qrzy88' }) - expect(bggXmlApiClient.get).toHaveBeenCalledWith('user', { name: 'Qrzy88' }) + expect(bggXmlApiClient.get).toHaveBeenCalledWith('user', { name: 'Qrzy88' }, {}) }) })