Skip to content
墨 AniLink

文書 · Documentation

AniLink

A typed TypeScript client for the AniList GraphQL and MyAnimeList REST APIs. One class, two isolated providers, normalized errors, retries, pacing, and a generated operation reference.

One client, two providers

Typed from install to response

Construct once with per-provider credentials. Each API is fully typed, from the variables you send to the responses you get back. The two providers never share a transport credential.

typescriptexample.ts
import { AniLink } from "anilink-api-wrapper";

// One client, two isolated providers.
const aniLink = new AniLink({
    anilist: { authToken: process.env.ANILIST_TOKEN },
    mal:     { accessToken: process.env.MAL_TOKEN },
});

// AniList: typed GraphQL, no token needed for public reads.
const anime = await aniLink.anilist.query.media({
    id: 21,
    type: "ANIME",
});
console.log(anime.media?.title?.romaji); // prints "One Piece"

// MyAnimeList: typed REST, public fields need no token.
const mal = await aniLink.mal.anime.get({ id: 21 }, {
    fields: ["id", "title", "main_picture"],
});
console.log(mal.title);

Why AniLink

The plumbing, done once

Calling AniList or MAL directly means hand-rolling HTTP, GraphQL documents, OAuth flows, retry logic, and rate-limit handling. AniLink does that once, with types.

  • Typed operations

    Every query, page query, and mutation ships with typed variables and a typed response, generated from the provider schemas. You never write GraphQL shapes by hand.

  • Normalized errors

    Provider failures become AniLinkError subclasses with stable code values. Classify failures by code, not by parsing message strings.

  • Resilience built in

    Retries use jittered backoff. You can turn on rate-limit pacing and a circuit breaker. Both providers get the same behavior.

  • Provider isolation

    Each provider slot has its own credentials and transport settings. A MAL token never reaches AniList, and vice versa.

  • Observability hooks

    onRequestStart, onSuccess, onRetry, and onError fire at every stage of the request lifecycle. Instrument calls without wrapping a single method.

  • Cancellation & timeouts

    Pass an AbortSignal or a per-request timeout. The transport cancels in flight, releases the attempt, and throws a typed cancellation error.

Two providers, one client

AniList & MyAnimeList

Both providers share a transport layer: timeouts, retries, pacing, the circuit breaker, hooks, and error normalization. They never share credentials.

AniList GraphQL MyAnimeList REST
ProtocolGraphQLREST
NamespaceaniLink.anilistaniLink.mal
OperationsQueries · Page · Mutations · custom()anime.get · seasonal · ranking · user.animeList · user.mangaList · user.me
AuthOAuth bearer tokenPKCE OAuth2 access token
Credential slotanilist.authTokenmal.accessToken

The documentation

Where to start reading

The docs form a single reading path. Begin with the start guides, move through the core transport concepts, then branch into provider-specific guides and the generated operation reference.

Ready to build?

Install the package and make your first typed call in under a minute.

AniLink, typed AniList & MyAnimeList client for TypeScript.