
Research
Supply Chain Attack on Axios Pulls Malicious Dependency from npm
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.
jikan-api.js
Advanced tools
A modern TypeScript wrapper for the Jikan API - the unofficial MyAnimeList API
A modern TypeScript wrapper for the Jikan API - the unofficial MyAnimeList API.
npm install jikan-api.js
yarn add jikan-api.js
pnpm add jikan-api.js
import Jikan from 'jikan-api.js';
// Initialize the client
const jikan = new Jikan();
// Get anime information
const anime = await jikan.anime.getAnimeByFullId(1);
console.log(anime.data.titles[0].title); // "Cowboy Bebop"
// Get manga information
const manga = await jikan.manga.getMangaByFullId(1);
console.log(manga.data.titles[0].title); // "Monster"
// Get character information
const character = await jikan.characters.getCharacterByFullId(1);
console.log(character.data.name); // "Spike Spiegel"
// Search for anime
const animeResults = await jikan.anime.searchAnime({
q: 'Naruto',
type: 'TV'
});
// Search for manga
const mangaResults = await jikan.manga.searchManga({
q: 'One Piece',
type: 'Manga'
});
new Jikan(baseUrl?: string)Creates a new Jikan API client instance.
// Using default Jikan API URL
const jikan = new Jikan();
// Using custom base URL (for testing or proxies)
const jikan = new Jikan('https://custom-api.example.com/v4');
getAnimeByFullId(id: number)Retrieves complete anime information by MyAnimeList ID.
const anime = await jikan.anime.getAnimeByFullId(1);
console.log({
title: anime.data.titles[0].title,
score: anime.data.score,
episodes: anime.data.episodes,
status: anime.data.status
});
searchAnime(params?: SearchParams)Search for anime with various filters.
// Basic search
const results = await jikan.anime.searchAnime({ q: 'Attack on Titan' });
// Advanced search with filters
const filteredResults = await jikan.anime.searchAnime({
q: 'Demon Slayer',
type: 'TV',
status: 'Finished Airing',
min_score: 8.0,
order_by: 'score',
sort: 'desc',
limit: 10
});
Search Parameters:
q?: string - Search querytype?: string - Anime type (TV, Movie, OVA, Special, ONA, Music)score?: number - Score filtermin_score?: number - Minimum scoremax_score?: number - Maximum scorestatus?: string - Airing statusrating?: string - Age ratingsfw?: boolean - Safe for work filtergenres?: string - Comma-separated genre IDsorder_by?: string - Field to order bysort?: string - Sort direction (asc, desc)page?: number - Page numberlimit?: number - Results per pagegetAnimeCharacters(id: number)Get character information for an anime.
const characters = await jikan.anime.getAnimeCharacters(1);
characters.data.forEach(char => {
console.log({
name: char.character.name,
role: char.role,
voiceActors: char.voice_actors.map(va => va.person.name)
});
});
getAnimeStaff(id: number)Get staff information for an anime.
const staff = await jikan.anime.getAnimeStaff(1);
staff.data.forEach(member => {
console.log({
name: member.person.name,
positions: member.positions
});
});
getAnimeEpisodes(id: number, page?: number)Get episode list for an anime.
// Get first page of episodes
const episodes = await jikan.anime.getAnimeEpisodes(1);
// Get specific page
const episodesPage2 = await jikan.anime.getAnimeEpisodes(1, 2);
episodes.data.forEach(episode => {
console.log({
number: episode.mal_id,
title: episode.title,
filler: episode.filler,
recap: episode.recap
});
});
getAnimeEpisodeById(id: number, episodeId: number)Get specific episode information.
const episode = await jikan.anime.getAnimeEpisodeById(1, 1);
console.log({
title: episode.data.title,
synopsis: episode.data.synopsis,
filler: episode.data.filler
});
getAnimeNews(id: number, page?: number)Get news articles related to an anime.
const news = await jikan.anime.getAnimeNews(1);
news.data.forEach(article => {
console.log({
title: article.title,
author: article.author_username,
date: article.date,
excerpt: article.excerpt
});
});
getAnimeReviews(id: number, page?: number)Get user reviews for an anime.
const reviews = await jikan.anime.getAnimeReviews(1);
reviews.data.forEach(review => {
console.log({
reviewer: review.user.username,
overallScore: review.scores.overall,
review: review.review.substring(0, 100) + '...',
episodesWatched: review.episodes_watched
});
});
getAnimeForum(id: number)Get forum topics related to an anime.
const forum = await jikan.anime.getAnimeForum(1);
forum.data.forEach(topic => {
console.log({
title: topic.title,
author: topic.author_username,
comments: topic.comments,
lastComment: topic.last_comment?.date_posted
});
});
getAnimeVideos(id: number)Get video content (trailers, promotional videos) for an anime.
const videos = await jikan.anime.getAnimeVideos(1);
console.log({
promoVideos: videos.data.promo.length,
episodes: videos.data.episodes.length,
musicVideos: videos.data.music_videos.length
});
getAnimePictures(id: number)Get picture gallery for an anime.
const pictures = await jikan.anime.getAnimePictures(1);
pictures.data.forEach(picture => {
console.log({
large: picture.large_image_url,
small: picture.small_image_url
});
});
getAnimeStatistics(id: number)Get viewing statistics for an anime.
const stats = await jikan.anime.getAnimeStatistics(1);
console.log({
watching: stats.data.watching,
completed: stats.data.completed,
onHold: stats.data.on_hold,
dropped: stats.data.dropped,
planToWatch: stats.data.plan_to_watch,
total: stats.data.total
});
getAnimeRecommendations(id: number)Get anime recommendations.
const recommendations = await jikan.anime.getAnimeRecommendations(1);
recommendations.data.forEach(rec => {
console.log({
title: rec.entry.title,
votes: rec.votes,
url: rec.entry.url
});
});
getAnimeRelations(id: number)Get related anime (sequels, prequels, etc.).
const relations = await jikan.anime.getAnimeRelations(1);
relations.data.forEach(relation => {
console.log({
relation: relation.relation,
entries: relation.entry.map(e => ({ name: e.name, type: e.type }))
});
});
getAnimeThemes(id: number)Get opening and ending themes.
const themes = await jikan.anime.getAnimeThemes(1);
console.log({
openings: themes.data.openings,
endings: themes.data.endings
});
getAnimeExternal(id: number)Get external links.
const external = await jikan.anime.getAnimeExternal(1);
external.data.forEach(link => {
console.log({
name: link.name,
url: link.url
});
});
getAnimeStreaming(id: number)Get streaming platform information.
const streaming = await jikan.anime.getAnimeStreaming(1);
streaming.data.forEach(platform => {
console.log({
name: platform.name,
url: platform.url
});
});
getAnimeMoreInfo(id: number)Get additional information.
const moreInfo = await jikan.anime.getAnimeMoreInfo(1);
console.log(moreInfo.data.moreinfo);
getAnimeUserUpdates(id: number, page?: number)Get recent user updates.
const updates = await jikan.anime.getAnimeUserUpdates(1);
updates.data.forEach(update => {
console.log({
user: update.user.username,
status: update.status,
episodesSeen: update.episodes_seen,
score: update.score,
date: update.date
});
});
getMangaByFullId(id: number)Retrieves complete manga information by MyAnimeList ID.
const manga = await jikan.manga.getMangaByFullId(1);
console.log({
title: manga.data.titles[0].title,
score: manga.data.score,
chapters: manga.data.chapters,
volumes: manga.data.volumes,
status: manga.data.status
});
getMangaById(id: number)Retrieves basic manga information by MyAnimeList ID.
const manga = await jikan.manga.getMangaById(1);
console.log({
title: manga.data.titles[0].title,
type: manga.data.type,
publishing: manga.data.publishing
});
searchManga(params?: SearchParams)Search for manga with various filters.
// Basic search
const results = await jikan.manga.searchManga({ q: 'One Piece' });
// Advanced search with filters
const filteredResults = await jikan.manga.searchManga({
q: 'Attack on Titan',
type: 'Manga',
status: 'Finished',
min_score: 8.0,
order_by: 'score',
sort: 'desc',
limit: 10
});
Search Parameters:
q?: string - Search querytype?: string - Manga type (Manga, Light Novel, One-shot, Doujinshi, Manhwa, Manhua, Novel)score?: number - Score filtermin_score?: number - Minimum scoremax_score?: number - Maximum scorestatus?: string - Publishing statussfw?: boolean - Safe for work filtergenres?: string - Comma-separated genre IDsorder_by?: string - Field to order bysort?: string - Sort direction (asc, desc)magazines?: string - Comma-separated magazine IDspage?: number - Page numberlimit?: number - Results per pagegetMangaCharacters(id: number)Get character information for a manga.
const characters = await jikan.manga.getMangaCharacters(1);
characters.data.forEach(char => {
console.log({
name: char.character.name,
role: char.role
});
});
getMangaNews(id: number, page?: number)Get news articles related to a manga.
const news = await jikan.manga.getMangaNews(1);
news.data.forEach(article => {
console.log({
title: article.title,
author: article.author_username,
date: article.date,
excerpt: article.excerpt
});
});
getMangaReviews(id: number, page?: number, preliminary?: boolean, spoilers?: boolean)Get user reviews for a manga.
const reviews = await jikan.manga.getMangaReviews(1);
reviews.data.forEach(review => {
console.log({
reviewer: review.user.username,
overallScore: review.scores.overall,
review: review.review.substring(0, 100) + '...',
chaptersRead: review.chapters_read
});
});
// Get reviews with filters
const filteredReviews = await jikan.manga.getMangaReviews(1, 1, true, false);
getMangaForum(id: number)Get forum topics related to a manga.
const forum = await jikan.manga.getMangaForum(1);
forum.data.forEach(topic => {
console.log({
title: topic.title,
author: topic.author_username,
comments: topic.comments,
lastComment: topic.last_comment?.date_posted
});
});
getMangaPictures(id: number)Get picture gallery for a manga.
const pictures = await jikan.manga.getMangaPictures(1);
pictures.data.forEach(picture => {
console.log({
large: picture.large_image_url,
small: picture.small_image_url
});
});
getMangaStatistics(id: number)Get reading statistics for a manga.
const stats = await jikan.manga.getMangaStatistics(1);
console.log({
reading: stats.data.reading,
completed: stats.data.completed,
onHold: stats.data.on_hold,
dropped: stats.data.dropped,
planToRead: stats.data.plan_to_read,
total: stats.data.total
});
getMangaRecommendations(id: number)Get manga recommendations.
const recommendations = await jikan.manga.getMangaRecommendations(1);
recommendations.data.forEach(rec => {
console.log({
title: rec.entry.title,
votes: rec.votes,
url: rec.entry.url
});
});
getMangaRelations(id: number)Get related manga/anime (sequels, prequels, etc.).
const relations = await jikan.manga.getMangaRelations(1);
relations.data.forEach(relation => {
console.log({
relation: relation.relation,
entries: relation.entry.map(e => ({ name: e.name, type: e.type }))
});
});
getMangaExternal(id: number)Get external links.
const external = await jikan.manga.getMangaExternal(1);
external.data.forEach(link => {
console.log({
name: link.name,
url: link.url
});
});
getMangaMoreInfo(id: number)Get additional information.
const moreInfo = await jikan.manga.getMangaMoreInfo(1);
console.log(moreInfo.data.moreinfo);
getMangaUserUpdates(id: number, page?: number)Get recent user updates.
const updates = await jikan.manga.getMangaUserUpdates(1);
updates.data.forEach(update => {
console.log({
user: update.user.username,
status: update.status,
chaptersRead: update.chapters_read,
volumesRead: update.volumes_read,
score: update.score,
date: update.date
});
});
getCharacterByFullId(id: number)Retrieves complete character information by MyAnimeList ID.
const character = await jikan.characters.getCharacterByFullId(1);
console.log({
name: character.data.name,
nameKanji: character.data.name_kanji,
nicknames: character.data.nicknames,
favorites: character.data.favorites,
about: character.data.about
});
getCharacterById(id: number)Retrieves basic character information by MyAnimeList ID.
const character = await jikan.characters.getCharacterById(1);
console.log({
name: character.data.name,
favorites: character.data.favorites,
url: character.data.url
});
getCharacterAnime(id: number)Get anime appearances for a character.
const animeAppearances = await jikan.characters.getCharacterAnime(1);
animeAppearances.data.forEach(appearance => {
console.log({
title: appearance.anime.title,
role: appearance.role,
url: appearance.anime.url
});
});
getCharacterManga(id: number)Get manga appearances for a character.
const mangaAppearances = await jikan.characters.getCharacterManga(1);
mangaAppearances.data.forEach(appearance => {
console.log({
title: appearance.manga.title,
role: appearance.role,
url: appearance.manga.url
});
});
getCharacterVoices(id: number)Get voice actor information for a character.
const voices = await jikan.characters.getCharacterVoices(1);
voices.data.forEach(voice => {
console.log({
voiceActor: voice.person.name,
language: voice.language,
url: voice.person.url
});
});
getCharacterPictures(id: number)Get picture gallery for a character.
const pictures = await jikan.characters.getCharacterPictures(1);
pictures.data.forEach(picture => {
console.log({
large: picture.large_image_url,
small: picture.small_image_url
});
});
The library throws errors for failed API requests:
try {
const anime = await jikan.anime.getAnimeByFullId(999999);
} catch (error) {
console.error('API Error:', error.message);
// Handle the error appropriately
}
This library is written in TypeScript and provides comprehensive type definitions:
import Jikan, { AnimeResponse, MangaResponse, CharacterResponse, JikanResponse } from 'jikan-api.js';
const jikan = new Jikan();
// Full type safety for anime
const anime: JikanResponse<AnimeResponse> = await jikan.anime.getAnimeByFullId(1);
// Full type safety for manga
const manga: JikanResponse<MangaResponse> = await jikan.manga.getMangaByFullId(1);
// Full type safety for characters
const character: JikanResponse<CharacterResponse> = await jikan.characters.getCharacterByFullId(1);
// TypeScript will provide autocomplete and type checking
console.log(anime.data.titles[0].title);
console.log(anime.data.score);
console.log(anime.data.episodes);
console.log(manga.data.titles[0].title);
console.log(manga.data.score);
console.log(manga.data.chapters);
console.log(character.data.name);
console.log(character.data.nicknames);
console.log(character.data.favorites);
Many endpoints support pagination:
// Check if more pages are available
const episodes = await jikan.anime.getAnimeEpisodes(1);
if (episodes.pagination?.has_next_page) {
const nextPage = await jikan.anime.getAnimeEpisodes(1, 2);
}
// Get pagination info
console.log({
currentPage: episodes.pagination?.current_page,
lastPage: episodes.pagination?.last_visible_page,
itemsPerPage: episodes.pagination?.items.per_page,
totalItems: episodes.pagination?.items.total
});
The Jikan API has rate limits. It's recommended to:
// Example with delay
async function getMultipleAnime(ids: number[]) {
const results = [];
for (const id of ids) {
const anime = await jikan.anime.getAnimeByFullId(id);
results.push(anime);
// Add delay to respect rate limits
await new Promise(resolve => setTimeout(resolve, 1000));
}
return results;
}
const topAnime = await jikan.anime.searchAnime({
order_by: 'score',
sort: 'desc',
limit: 10
});
console.log('Top 10 Anime:');
topAnime.data.forEach((anime, index) => {
console.log(`${index + 1}. ${anime.titles[0].title} (Score: ${anime.score})`);
});
// Get action anime (genre ID 1)
const actionAnime = await jikan.anime.searchAnime({
genres: '1',
order_by: 'popularity',
sort: 'asc',
limit: 5
});
console.log('Popular Action Anime:');
actionAnime.data.forEach(anime => {
console.log(`${anime.titles[0].title} - Episodes: ${anime.episodes}`);
});
async function getAnimeDetails(id: number) {
// Get all information about an anime
const [
anime,
characters,
staff,
episodes,
reviews,
stats
] = await Promise.all([
jikan.anime.getAnimeByFullId(id),
jikan.anime.getAnimeCharacters(id),
jikan.anime.getAnimeStaff(id),
jikan.anime.getAnimeEpisodes(id),
jikan.anime.getAnimeReviews(id),
jikan.anime.getAnimeStatistics(id)
]);
return {
basic: anime.data,
characters: characters.data,
staff: staff.data,
episodes: episodes.data,
reviews: reviews.data,
statistics: stats.data
};
}
// Usage
const fullDetails = await getAnimeDetails(1);
console.log('Full anime details:', fullDetails);
const topManga = await jikan.manga.searchManga({
order_by: 'score',
sort: 'desc',
limit: 10
});
console.log('Top 10 Manga:');
topManga.data.forEach((manga, index) => {
console.log(`${index + 1}. ${manga.titles[0].title} (Score: ${manga.score})`);
});
// Get romance manga (genre ID 22)
const romanceManga = await jikan.manga.searchManga({
genres: '22',
order_by: 'popularity',
sort: 'asc',
limit: 5
});
console.log('Popular Romance Manga:');
romanceManga.data.forEach(manga => {
console.log(`${manga.titles[0].title} - Chapters: ${manga.chapters || 'Ongoing'}`);
});
async function getMangaDetails(id: number) {
// Get all information about a manga
const [
manga,
characters,
news,
reviews,
stats,
recommendations
] = await Promise.all([
jikan.manga.getMangaByFullId(id),
jikan.manga.getMangaCharacters(id),
jikan.manga.getMangaNews(id),
jikan.manga.getMangaReviews(id),
jikan.manga.getMangaStatistics(id),
jikan.manga.getMangaRecommendations(id)
]);
return {
basic: manga.data,
characters: characters.data,
news: news.data,
reviews: reviews.data,
statistics: stats.data,
recommendations: recommendations.data
};
}
// Usage
const fullMangaDetails = await getMangaDetails(1);
console.log('Full manga details:', fullMangaDetails);
async function compareAnimeAndManga(animeId: number, mangaId: number) {
const [anime, manga] = await Promise.all([
jikan.anime.getAnimeByFullId(animeId),
jikan.manga.getMangaByFullId(mangaId)
]);
console.log('Comparison:');
console.log(`Anime: ${anime.data.titles[0].title} - Score: ${anime.data.score}`);
console.log(`Manga: ${manga.data.titles[0].title} - Score: ${manga.data.score}`);
return {
anime: anime.data,
manga: manga.data,
animeScore: anime.data.score,
mangaScore: manga.data.score
};
}
// Usage
const comparison = await compareAnimeAndManga(1, 1);
async function getCharacterDetails(id: number) {
// Get all information about a character
const [
character,
animeAppearances,
mangaAppearances,
voices,
pictures
] = await Promise.all([
jikan.characters.getCharacterByFullId(id),
jikan.characters.getCharacterAnime(id),
jikan.characters.getCharacterManga(id),
jikan.characters.getCharacterVoices(id),
jikan.characters.getCharacterPictures(id)
]);
return {
basic: character.data,
animeAppearances: animeAppearances.data,
mangaAppearances: mangaAppearances.data,
voiceActors: voices.data,
pictures: pictures.data
};
}
// Usage
const characterDetails = await getCharacterDetails(1);
console.log('Character details:', characterDetails);
async function getCharacterVoiceActors(characterId: number) {
const voices = await jikan.characters.getCharacterVoices(characterId);
const voiceActorsByLanguage = voices.data.reduce((acc, voice) => {
if (!acc[voice.language]) {
acc[voice.language] = [];
}
acc[voice.language].push({
name: voice.person.name,
url: voice.person.url
});
return acc;
}, {} as Record<string, Array<{name: string, url: string}>>);
return voiceActorsByLanguage;
}
// Usage
const voiceActors = await getCharacterVoiceActors(1);
console.log('Japanese VAs:', voiceActors.Japanese);
console.log('English VAs:', voiceActors.English);
async function analyzeCharacterAppearances(characterId: number) {
const [animeAppearances, mangaAppearances] = await Promise.all([
jikan.characters.getCharacterAnime(characterId),
jikan.characters.getCharacterManga(characterId)
]);
const stats = {
totalAnime: animeAppearances.data.length,
totalManga: mangaAppearances.data.length,
mainRoles: {
anime: animeAppearances.data.filter(a => a.role === 'Main').length,
manga: mangaAppearances.data.filter(m => m.role === 'Main').length
},
supportingRoles: {
anime: animeAppearances.data.filter(a => a.role === 'Supporting').length,
manga: mangaAppearances.data.filter(m => m.role === 'Supporting').length
}
};
return {
stats,
animeList: animeAppearances.data.map(a => ({ title: a.anime.title, role: a.role })),
mangaList: mangaAppearances.data.map(m => ({ title: m.manga.title, role: m.role }))
};
}
// Usage
const analysis = await analyzeCharacterAppearances(1);
console.log('Character appeared in', analysis.stats.totalAnime, 'anime and', analysis.stats.totalManga, 'manga');
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)# Clone the repository
git clone https://github.com/OpenianDevelopment/jikan-api.js.git
cd jikan-api.js
# Install dependencies
npm install
# Run tests
npm test
# Build the project
npm run build
# Run tests in watch mode
npm run test:watch
# Build in watch mode
npm run dev
This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ by Rohan Kumar
FAQs
A modern TypeScript wrapper for the Jikan API - the unofficial MyAnimeList API
We found that jikan-api.js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.

Security News
TeamPCP is partnering with ransomware group Vect to turn open source supply chain attacks on tools like Trivy and LiteLLM into large-scale ransomware operations.