Skip to content
This repository has been archived by the owner on Nov 6, 2021. It is now read-only.

Commit

Permalink
fix(getqueriedgamesamerica): fixed getQueriedGamesAmerica which was b…
Browse files Browse the repository at this point in the history
…roken as per API changes

Along with this change the return structure has also changed so this is a breaking change

BREAKING CHANGE: The return structure has changed. Please refer to updated documentation or
TypeScript information.

re #374
  • Loading branch information
favna committed Mar 5, 2021
1 parent bc09b4e commit 5c32023
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 55 deletions.
19 changes: 9 additions & 10 deletions __tests__/getQueriedGamesAmerica.test.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { getQueriedGamesAmerica } from '../src';

describe('getQueriedGamesAmerica', () => {
test('GIVEN Zelda THEN returns at least XXX results', async () => {
test('GIVEN Zelda THEN returns results with some known games', async () => {
const data = await getQueriedGamesAmerica('Zelda');

expect(data).toBeInstanceOf(Object);
expect(data.length).toBeGreaterThanOrEqual(20);

// Expect Link's Awakening to be in the data
expect(data).toEqual(
expect.arrayContaining([
// Expect Link's Awakening to be in the data
expect.objectContaining({
title: "The Legend of Zelda: Link's Awakening"
})
])
);

// Expect Breath of the Wild to be in the data
expect(data).toEqual(
expect.arrayContaining([
title: 'The Legend of Zelda™: Link’s Awakening'
}),
// Expect Breath of the Wild to be in the data
expect.objectContaining({
title: 'The Legend of Zelda: Breath of the Wild'
}),
// Expect Skyward Sword to be in the data
expect.objectContaining({
title: 'The Legend of Zelda™: Skyward Sword HD'
})
])
);
Expand Down
29 changes: 13 additions & 16 deletions src/lib/getGames/getQueriedGamesAmerica.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fetch from 'node-fetch';
import { stringify } from 'querystring';
import { QUERIED_US_ALGOLIA_KEY, US_ALGOLIA_HEADERS, US_GET_GAMES_URL } from '../utils/constants';
import type { AlgoliaResponse, QueriedGameUS } from '../utils/interfaces';
import type { QueriedGameResult, QueriedGamesAmericaOptions, QueriedGameUS } from '../utils/interfaces';
import { EshopError } from '../utils/utils';

/**
Expand All @@ -11,33 +11,30 @@ import { EshopError } from '../utils/utils';
* @license Apache-2.0 Favna & Antonio Román
* @copyright 2019
*/
export const getQueriedGamesAmerica = async (query: string): Promise<QueriedGameUS[]> => {
export const getQueriedGamesAmerica = async (
query: string,
{ hitsPerPage = 200, page = 0 }: QueriedGamesAmericaOptions = { hitsPerPage: 200, page: 0 }
): Promise<QueriedGameUS[]> => {
const response = await fetch(US_GET_GAMES_URL, {
method: 'POST',
headers: {
...US_ALGOLIA_HEADERS,
'X-Algolia-API-Key': QUERIED_US_ALGOLIA_KEY
},
body: JSON.stringify({
requests: [
{
indexName: 'noa_aem_game_en_us',
params: stringify({
facetFilters: ['type:game'],
hitsPerPage: 200,
page: 0,
query
})
}
]
params: stringify({
hitsPerPage,
page,
query
})
})
});

if (!response.ok) throw new EshopError(`Fetching games for the query "${query} failed"`);

const { results }: AlgoliaResponse<QueriedGameUS> = await response.json();
const { hits }: QueriedGameResult = await response.json();

if (!results.length) throw new EshopError(`No game results for the query "${query}"`);
if (!hits.length) throw new EshopError(`No game results for the query "${query}"`);

return results[0].hits;
return hits;
};
4 changes: 2 additions & 2 deletions src/lib/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ export const US_ALGOLIA_ID = 'U3B6GR4UA3';
export const US_ALGOLIA_KEY = 'c4da8be7fd29f0f5bfa42920b0a99dc7';

/** Algolia key for getting US games with a query */
export const QUERIED_US_ALGOLIA_KEY = '9a20c93440cf63cf1a7008d75f7438bf';
export const QUERIED_US_ALGOLIA_KEY = '6efbfb0f8f80defc44895018caf77504';

/** URL for getting US Games */
export const US_GET_GAMES_URL = `https://${US_ALGOLIA_ID}-dsn.algolia.net/1/indexes/*/queries`;
export const US_GET_GAMES_URL = `https://${US_ALGOLIA_ID}-dsn.algolia.net/1/indexes/ncom_game_en_us/query`;

/**
* Sample game code for US store
Expand Down
137 changes: 110 additions & 27 deletions src/lib/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,38 +59,121 @@ export interface GameEU {
title_extras_txt: string[];
}

/** Additional options for the [[getQueriedGamesAmerica]] method */
export interface QueriedGamesAmericaOptions {
/**
* The amount of hits to be received per page
* @minimum 0
* @maximum 200
* @default 200
*/
hitsPerPage?: number;
/**
* The page number to get
* @minimum 0
* @default 0
*/
page?: number;
}

export interface QueriedGameResult {
/** The hits for this query */
hits: QueriedGameUS[];
/** The amount of hits */
nbHits: number;
/** The page that the result is on */
page: number;
/** The amount of pages available */
nbPages: number;
/** The amount of hits per page */
hitsPerPage: number;
/** Whether the amount of hits is exhaustive or not */
exhaustiveNbHits: true;
/** The query that was used */
query: string;
/** The params that were used */
params: string;
/** The amount of time it took the {@link https://www.nintendo.com nintendo.com} API to process this request */
processingTimeMS: number;
}

export interface QueriedGameUS {
type: string;
locale: string;
url: string;
title: string;
/** Whether this game is available or not */
availability: string[];
/** The box art of the game, if any. Generally undefined for games that are yet to release. */
boxart?: string;
/** A description about this game */
description: string;
/** A list of companies that developed this game */
developers: string[];
/** A list of {@link https://www.esrb.org/ratings-guide/ ESRB descriptors} */
esrbDescriptors: string[];
/** The {@link https://www.esrb.org/ratings-guide/ ESRB Rating} */
esrbRating: string;
/** Whether this game is featured on the {@link https://www.nintendo.com nintendo.com} homepage */
featured: boolean;
/** The franchises this game is a part of */
franchises: string;
/** Whether this game is free to start */
freeToStart: boolean;
/** A list of general filters that could potentially be searched on {@link https://www.nintendo.com nintendo.com} to find this game with */
generalFilters: string[];
/** A list of genres this game */
genres: string[];
/** A large wide image such as a screenshot or artwork of the game, if any. */
horizontalHeaderImage?: string;
/** A list of methods through which the game can be acquired, such as retail or digital download. */
howToShop: string[];
/** A Unix timestamp in **milliseconds** indicating when the information on this game was last modified */
lastModified: number;
id: string;
/** The lowest price at which this game was ever sold */
lowestPrice: number;
/** The {@link https://en.wikipedia.org/wiki/List_price manufacturer's suggested retail price} for this game */
msrp: number;
/** The unique ID for this game. */
nsuid: string;
slug: string;
boxArt: string;
gallery: string;
/** The amount of players that can simultaneously play this game */
numOfPlayers: string;
/** A unique {@link https://en.wikipedia.org/wiki/Universally_unique_identifier GUID} that represents this game's entry in the Nintendo API. */
objectID: string;
/** The platform this game released on */
platform: string;
releaseDateMask: string;
characters: string[];
categories: string[];
msrp: number | null;
esrb?: string;
esrbDescriptors?: string[];
virtualConsole: string;
generalFilters: string[];
filterShops: string[];
filterPlayers: string[];
/** A list of player filters that could potentially be searched on {@link https://www.nintendo.com nintendo.com} to find this game with */
playerFilters: string[];
/** A category price range that this game falls under. Can be used on {@link https://www.nintendo.com nintendo.com} to find this game with */
priceRange: string;
/** A list of companies that published this game */
publishers: string[];
developers: string[];
players: string;
featured: boolean;
freeToStart: boolean;
priceRange: string | null;
/**
* A display of the release of this game. Can be either an ISO timestamp or some other representation of date.
* @remark Nintendo has a tendency to also have entries such as `Early 2022` or `Late 2021` here. Normally these kinds of dates would not be parsed by JavaScript, but NodeJS does parse these natural input types.
*/
releaseDateDisplay: string;
/** The price of this game if and when it is on sale */
salePrice: number | null;
availability: string[];
objectID: string;
/** A unique {@link https://en.wikipedia.org/wiki/Clean_URL#Slug slug} for this game */
slug: string;
/** The title of this game */
title: string;
/** A unique to the information about this game. Prefix it with `https://www.nintendo.com` to have a valid URL. */
url: string;
/** Additional information returned by the API, it doesn't really serve any purpose but documenting it anyway because it's there. */
_distinctSeqID: number;
/** Additional information returned by the API, it doesn't really serve any purpose but documenting it anyway because it's there. */
_highlightResult: HighlightResult;
}

export interface HighlightResult {
title: Nsuid;
nsuid: Nsuid;
publishers: Nsuid[];
}

export interface Nsuid {
value: string;
matchLevel: string;
matchedWords: string[];
fullyHighlighted?: boolean;
}

export interface GameUS {
Expand Down Expand Up @@ -145,8 +228,8 @@ interface AlgoliaResults<T extends GameUS | QueriedGameUS> {
}

/** @internal */
export interface AlgoliaResponse<T extends GameUS | QueriedGameUS> {
results: AlgoliaResults<T>[];
export interface AlgoliaResponse {
results: AlgoliaResults<GameUS>[];
}

export interface GameJP extends Record<string, string | number | undefined> {
Expand Down

0 comments on commit 5c32023

Please sign in to comment.