Skip to content

Commit

Permalink
@thunderstore/thunderstore-api: add two package listing fetchers
Browse files Browse the repository at this point in the history
One will fetch package listings scoped on a specific community, while
the other scopes for both community and namespace.

Both fetchers use the same arguments to order, paginatem, and filter
the package listings. Fetchers receive these arguments as a single
object, for which the interface is exported from the package. I would
have liked them to get the args separately for simplicity's and
consistency's sake, but that would have lead to lot of boilerplate code
both in thunderstore-api and in dapper-ts. Especially when more package
listing fetchers are added in the future.

Refs TS-1875
  • Loading branch information
anttimaki committed Nov 10, 2023
1 parent c289a48 commit 22d273d
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { config } from "./defaultConfig";
import { fetchCommunityPackageListings } from "../communityPackageListings";

interface PartialPackage {
community_identifier: string;
}

it("receives community scoped paginated package listing", async () => {
const communityId = "riskofrain2";
const response = await fetchCommunityPackageListings(config, communityId);

expect(typeof response.count).toEqual("number");
expect(Array.isArray(response.results)).toEqual(true);

response.results.forEach((pkg: PartialPackage) => {
expect(pkg.community_identifier.toLowerCase()).toStrictEqual(communityId);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { config } from "./defaultConfig";
import { fetchNamespacePackageListings } from "../namespacePackageListings";

interface PartialPackage {
community_identifier: string;
namespace: string;
}

it("receives namespace scoped paginated package listing", async () => {
const communityId = "riskofrain2";
const namespaceId = "testteam";
const response = await fetchNamespacePackageListings(
config,
communityId,
namespaceId
);

expect(typeof response.count).toEqual("number");
expect(Array.isArray(response.results)).toEqual(true);

response.results.forEach((pkg: PartialPackage) => {
expect(pkg.community_identifier.toLowerCase()).toStrictEqual(communityId);
expect(pkg.namespace.toLowerCase()).toStrictEqual(namespaceId);
});
});
26 changes: 26 additions & 0 deletions packages/thunderstore-api/src/fetch/communityPackageListings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { RequestConfig } from "../index";
import { apiFetch } from "../apiFetch";
import { serializeQueryString } from "../queryString";
import { PackageListingQueryParams } from "../types";

export async function fetchCommunityPackageListings(
config: RequestConfig,
communityId: string,
options?: PackageListingQueryParams
) {
const path = `api/cyberstorm/package/${communityId.toLowerCase()}/`;

const queryParams = [
{ key: "ordering", value: options?.ordering, impotent: "last-updated" },
{ key: "page", value: options?.page, impotent: 1 },
{ key: "q", value: options?.q.trim() },
{ key: "included_categories", value: options?.includedCategories },
{ key: "excluded_categories", value: options?.excludedCategories },
{ key: "section", value: options?.section },
{ key: "nsfw", value: options?.nsfw, impotent: false },
{ key: "deprecated", value: options?.deprecated, impotent: false },
];
const query = serializeQueryString(queryParams);

return await apiFetch(config, path, query);
}
27 changes: 27 additions & 0 deletions packages/thunderstore-api/src/fetch/namespacePackageListings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { RequestConfig } from "../index";
import { apiFetch } from "../apiFetch";
import { serializeQueryString } from "../queryString";
import { PackageListingQueryParams } from "../types";

export async function fetchNamespacePackageListings(
config: RequestConfig,
communityId: string,
namespaceId: string,
options?: PackageListingQueryParams
) {
const path = `api/cyberstorm/package/${communityId.toLowerCase()}/${namespaceId.toLowerCase()}/`;

const queryParams = [
{ key: "ordering", value: options?.ordering, impotent: "last-updated" },
{ key: "page", value: options?.page, impotent: 1 },
{ key: "q", value: options?.q.trim() },
{ key: "included_categories", value: options?.includedCategories },
{ key: "excluded_categories", value: options?.excludedCategories },
{ key: "section", value: options?.section },
{ key: "nsfw", value: options?.nsfw, impotent: false },
{ key: "deprecated", value: options?.deprecated, impotent: false },
];
const query = serializeQueryString(queryParams);

return await apiFetch(config, path, query);
}
2 changes: 2 additions & 0 deletions packages/thunderstore-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export interface RequestConfig {
export * from "./fetch/community";
export * from "./fetch/communityFilters";
export * from "./fetch/communityList";
export * from "./fetch/communityPackageListings";
export * from "./fetch/currentUser";
export * from "./fetch/namespacePackageListings";
export * from "./fetch/teamDetails";
export * from "./fetch/teamMembers";
export * from "./fetch/teamServiceAccounts";
26 changes: 26 additions & 0 deletions packages/thunderstore-api/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Parameters for ordering, paginating, and filtering package lists.
*/
export interface PackageListingQueryParams {
/** Ordering for the results */
ordering: string;
/** Page number for the paginated results */
page: number;
/** Free text search for filtering e.g. by package name */
q: string;
/** Ids of categories the package MUST belong to */
includedCategories: number[];
/** Ids of categories the package MUST NOT belong to */
excludedCategories: number[];
/**
* UUID of community's section the package MUST fit.
*
* Sections are community-specific shorthands for filtering by
* multiple included and excluded categories at once.
* */
section: string;
/** Should NSFW packages be included (by default they're not) */
nsfw: boolean;
/** Should deprecated packages be included (by default they're not) */
deprecated: boolean;
}

0 comments on commit 22d273d

Please sign in to comment.