These examples are written as copyable starting points. They assume you already have a client:
import { IGDBClient } from "@api-wrappers/igdb-wrapper";
const client = new IGDBClient({
clientId: process.env.TWITCH_CLIENT_ID!,
clientSecret: process.env.TWITCH_CLIENT_SECRET!,
});For full files, see ../examples.
Use endpoint.search(term) for IGDB full-text search. It returns a normal query builder, so you can still select fields, filter, sort, and limit.
const games = await client.games
.search("zelda")
.select((game) => ({
id: game.id,
name: game.name,
slug: game.slug,
rating: game.rating,
cover: {
imageId: game.cover.image_id,
},
}))
.where((game) => game.rating.gte(70))
.limit(10)
.execute();Use findById() when you already have the IGDB ID. It returns the first
matching game or throws IGDBNotFoundError.
const game = await client.games.findById(1942);
console.log(game.name);Use select() to keep IGDB field paths typed while shaping the result for your
application. The object keys become the returned TypeScript shape.
const games = await client.games
.query()
.select((game) => ({
id: game.id,
title: game.name,
summary: game.summary,
releaseDate: game.first_release_date,
cover: {
imageId: game.cover.image_id,
},
}))
.limit(12)
.execute();
for (const game of games) {
console.log(game.title, game.releaseDate);
}APICalypse can express dense filters, but the typed helpers make common comparisons easier to maintain.
const games = await client.games
.query()
.select((game) => ({
name: game.name,
rating: game.rating,
releaseDate: game.first_release_date,
}))
.where((game) => [
game.rating.gte(80),
game.first_release_date.gte(1672531200),
game.platforms.containsAll([48, 6]),
])
.limit(20)
.execute();Use whereRaw() when the exact IGDB expression is clearer than a typed helper:
const consoleGames = await client.games
.query()
.fields("name", "platforms.name")
.whereRaw("platforms = {48,6}")
.limit(10)
.execute();const topRated = await client.games
.query()
.select((game) => ({
name: game.name,
rating: game.rating,
ratingCount: game.rating_count,
}))
.where((game) => game.rating_count.gte(100))
.sort((game) => game.rating, "desc")
.limit(10)
.execute();IGDB returns image IDs. Use buildImageUrl() to produce a CDN URL.
import { buildImageUrl } from "@api-wrappers/igdb-wrapper";
const coverUrl = game.cover?.imageId
? buildImageUrl(game.cover.imageId, {
size: "cover_big",
retina: true,
extension: "webp",
})
: null;Keep a reusable base query, then branch it into execute() and count(). Query builders are immutable, so limit() and offset() do not mutate the base query.
const pageSize = 20;
const pageIndex = 0;
const baseQuery = client.games
.query()
.select((game) => ({
id: game.id,
name: game.name,
rating: game.rating,
ratingCount: game.rating_count,
}))
.where((game) => game.rating_count.gte(100))
.sort((game) => game.rating, "desc");
const [items, total] = await Promise.all([
baseQuery.limit(pageSize).offset(pageIndex * pageSize).execute(),
baseQuery.count(),
]);Use paginate() for jobs, imports, and background syncs where you want to walk through every page until IGDB returns fewer records than requested.
for await (const page of client.games
.query()
.select((game) => ({ id: game.id, name: game.name }))
.where((game) => game.first_release_date.notNull())
.paginate(100)) {
for (const game of page) {
console.log(game.id, game.name);
}
}Use typed helpers for the readable parts and raw APICalypse for expressions that are more compact in IGDB syntax.
const games = await client.games
.query()
.fields("name", "platforms.name", "genres.name", "cover.image_id")
.where((game) => game.rating.gte(80))
.whereRaw("platforms = {48,6}")
.limit(10)
.execute();raw() returns the compiled query string. explain() logs it and returns the same builder so you can keep chaining.
const query = client.games
.query()
.where((game) => game.rating.gte(90))
.sort((game) => game.rating, "desc")
.limit(5);
console.log(query.raw());
const games = await query.explain().execute();Use metadata while building admin tools, schema explorers, or diagnostics.
const fields = await client.games.meta();
for (const field of fields) {
console.log(field.name, field.type);
}Multi-query is useful when a screen needs several unrelated datasets in one IGDB request. This wrapper exposes IGDB's raw multi-query body through client.multiQuery(); a typed multi-query builder is not available yet.
const response = await client.multiQuery(`
query games "Top Games" {
fields name,rating;
sort rating desc;
limit 5;
};
query platforms/count "Platform Count" {
};
`);
const topGames = response.find((entry) => entry.name === "Top Games")?.result;
const platformCount = response.find(
(entry) => entry.name === "Platform Count",
)?.count;import {
IGDBAuthError,
IGDBNotFoundError,
IGDBRateLimitError,
IGDBValidationError,
} from "@api-wrappers/igdb-wrapper";
try {
const game = await client.games.findById(999999999);
console.log(game.name);
} catch (error) {
if (error instanceof IGDBNotFoundError) {
console.log("No game found");
} else if (error instanceof IGDBAuthError) {
console.error("Check TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET");
} else if (error instanceof IGDBRateLimitError) {
console.error(`Rate limited. Retry after ${error.retryAfterMs ?? 0}ms`);
} else if (error instanceof IGDBValidationError) {
throw error;
} else {
throw error;
}
}const webhook = await client.createWebhook("games", {
method: "create",
secret: process.env.IGDB_WEBHOOK_SECRET!,
url: "https://example.com/igdb/webhooks/games",
});
await client.testWebhook("games", webhook.id, 1942);
const hooks = await client.listWebhooks();
console.log(hooks.map((hook) => hook.url));