Skip to content
AniLink

Custom queries

anilist.custom() sends a GraphQL document you write. Use it when a field combination is not exposed by the typed operations.

typescript
const result = await aniLink.anilist.custom<{ Media: { id: number; title: { romaji: string } } }>(
    "query ($id: Int) { Media(id: $id) { id title { romaji } } }",
    { id: 21 }
);
console.log(result.Media.title.romaji);

Generic typing

custom<T> types the unwrapped result. Declare T as the shape of what the document returns after unwrapping (see the rule below).

Envelope-unwrapping rule

The return shape depends on how many root fields your document has:

Document shapeReturn value
Single root field (query { Media { … } })The bare value of that field — e.g. { id, title }
Multiple root fields (query { Media { … } Viewer { … } })The full { data } envelope — e.g. { data: { Media: …, Viewer: … } }
typescript
// Single root field: T is the field's value.
const media = await aniLink.anilist.custom<{ id: number }>(
    "query { Media(id: 1) { id } }"
);
media.id; // direct access

// Multi-root: T is the envelope.
const both = await aniLink.anilist.custom<{ data: { Media: { id: number }; Viewer: { id: number } } }>(
    "query { Media(id: 1) { id } Viewer { id } }",
    undefined,
    { timeout: 10_000 } // optional per-request transport settings
);
both.data.Media.id;

Errors

custom() throws the same normalized errors as typed operations: AniLinkGraphQLError for GraphQL-level failures (with partial data when present), AniLinkApiError for HTTP failures, AniLinkNetworkError for transport failures.

Next steps

AniLink — typed AniList & MyAnimeList client for TypeScript.