An UNOFFICIAL wrapper for the anilist api written in typescript that tries to follow the builder pattern to give a more consistent interface to create objects.
You can visit the official graphql docs for anilist here to find out everything you can do[^*].
To see the current status of the wrapper check the todo list.
Warning As of v0.12 the only way to create queries is
query.<queryName>
npm i anilist
const query = anilist.query.media();
The queries can accept either an object of MediaArguments
or a string.
If you pass in a string it will be transformed into { search: string }
internally.
const queryByName = anilist.query.media("Kamisama Ni Natta Hi");
/*
query {
Media(type: ANIME, search: "Kamisama Ni Natta Hi") {
id
}
}
*/
const queryById = anilist.query.media({
id: 118419
});
/*
query {
Media(type: ANIME, id: 118419) {
id
}
}
*/
if you build the query and fetch it without telling which fields to return it will default to returning { media: { id } }
with { page: 1, perPage: 10 }
const query = anilist.pageQuery()
await query.fetch()
/*
{
media: [
{ id: 1 }, { id: 5 },
{ id: 6 }, { id: 7 },
{ id: 8 }, { id: 15 },
{ id: 16 }, { id: 17 },
{ id: 18 }, { id: 19 }
]
}
*/
query.withMedia(media => media.withTitles())
await query.fetch()
/*
{
media: [
{ title: { romaji: 'Cowboy Bebop' } },
{ title: { romaji: 'Cowboy Bebop: Tengoku no Tobira' } },
{ title: { romaji: 'TRIGUN' } },
{ title: { romaji: 'Witch Hunter ROBIN' } },
{ title: { romaji: 'Bouken Ou Beet' } },
{ title: { romaji: 'Eyeshield 21' } },
{ title: { romaji: 'Hachimitsu to Clover' } },
{ title: { romaji: 'Hungry Heart: Wild Striker' } },
{ title: { romaji: 'Initial D FOURTH STAGE' } },
{ title: { romaji: 'MONSTER' } }
]
}
*/
If you build the query and try to fetch it without telling which fields to return it will default to returning id
to avoid errors.
const query = anilist.query.media("Kamisama Ni Natta Hi");
await query.fetch();
/*
{ id: 118419 }
*/
query.withEpisodes();
await query.fetch();
/*
{ episodes: 12 }
*/
As the library follows the builder pattern you can just nest functions until you have every field you want.
const query = anilist.query.media("Kamisama Ni Natta Hi")
.withId()
.withSiteUrl()
.withTitles()
.withStatus();
await query.fetch();
/*
{
id: 118419,
siteUrl: 'https://anilist.co/anime/118419',
title: {
romaji: 'Kamisama ni Natta Hi'
},
status: 'FINISHED'
}
*/
All relations that use edges and nodes will have the following structure
anilist.query.media().withRelations({
edges: (edge) => edge.withId().withNode((node) => node.withId()),
nodes: (node) => node.withId(),
pageInfo: (page) => page.withTotal(),
// And optionally they will have an args object
})
Instead of passing the query arguments on query creation you can use <query.media>.prototype.arguments
to change them every time you want to run fetch. This will avoid creating a new query instance every time you change something on it.
const query = anilist.query.media();
await query.fetch()
/*
{ id: 1 }
*/
query.arguments({
search: "Kamisama Ni Natta",
type: "MANGA"
}).withId().withTitles("romaji", "native")
await query.fetch()
/*
{
id: 135190,
title: { romaji: 'Kamisama ni Natta Hi', native: '神様になった日' }
}
*/
The library provides 2 helpers methods for OAuth and i will explain them here
Remember: All options can be passed to the client constructor so you don't have to pass them in every function
createOAuthURI
This method returns the url with all required properties
//
const uri = anilist.createOAuthURI({
clientId: /* the id (can be an number or string) */,
responseType: "token"
});
const uri = const uri = anilist.createOAuthURI({
clientId: /* the id (can be an number or string) */,
responseType: "code"
})
getAccessToken
This helper method allows you to convert the Authorization Code Grant into an access token
const response = anilist.getAccessToken(codeGrant, {
clientId: /* the id (can be an number or string) */,
clientSecret: /* the client secret */,
redirectUri: /* the redirect uri, this is required for this step*/,
})
[^*]: Not everything is supported yet, please refer to the todo list to see what has full implementation or open an issue to talk about it