Skip to content

daniyal-abbassi/Next.js-animeAPI

Repository files navigation

Next.js Learning Project – Anime Explorer

Next.js TypeScript Bootstrap API Status

A hands-on learning project to explore modern Next.js App Router patterns using the Jikan (MyAnimeList) API. The main focus is understanding how Next.js differs from plain React and how it simplifies real-world app flows.


Table of Contents


Goals

  1. Learn the App Router mindset in Next.js (layouts, server-first, routing).
  2. Practice data-fetching patterns and URL-driven state (no heavy client state).
  3. Implement practical UI features: search, filters, pagination, skeleton loading.
  4. Understand rendering strategies: static, dynamic, streaming.
  5. Handle errors gracefully with error and not-found routes.

Key Learnings

Server vs Client Components

  • Server Components (default): fetch data securely on the server, no bundle cost on the client, great for SEO and performance.
  • Client Components (with "use client"): needed for interactivity (inputs, onChange, onClick, router hooks).
  • Practical split used here:
    • Server: building the board grid
    • Client: search input, filter controls, pagination links

URLSearchParams over useState

  • Instead of local component state, the app encodes UI state in the URL.
  • Flow learned and applied:
    1. Read current params with useSearchParams in client components
    2. Update them using URLSearchParams + useRouter().replace()
    3. Server components re-render automatically based on searchParams
  • Benefits: shareable URLs, back/forward nav works, SSR-friendly, fewer client states to manage.

Pagination, Skeletons, and Filters

  • Pagination numbers generated with a helper that returns numbers and ellipses.
  • Skeletons displayed while data is loading to keep layout stable.
  • Filters (e.g., sfw, type, status, rating, order_by, sort) map to API query parameters and are encoded in the URL.

Static, Dynamic, and Streaming Rendering

  • Static: layout and some non-parameterized UI render once per route.
  • Dynamic: pages/components depending on searchParams or dynamic data fetches.
  • Streaming: leverage async server components and Suspense to progressively render content and skeletons for faster perceived performance.

Error Handling and Resets

  • Dedicated error.tsx and not-found.tsx routes handle failures.
  • Reset behavior falls back to reloading or navigating to the root when needed.
  • Server component error UI uses a simple form submit to retry (no onClick in server components).

Tech Stack

  • Next.js 15 (App Router)
  • TypeScript
  • Bootstrap 5 (styling)
  • next/image with remote patterns for cdn.myanimelist.net
  • Jikan API (MyAnimeList) v4

Folder Structure

nextjs-anime-api/
├─ app/                         # Route tree (App Router)
│  ├─ styles/                   # Scoped CSS modules
│  │  ├─ styles.module.css
│  │  ├─ styles.board.module.css
│  │  ├─ styles.filters.module.css
│  │  ├─ styles.navbar.module.css
│  │  ├─ styles.pagination.module.css
│  │  ├─ styles.search.module.css
│  │  └─ styles.skeleton.module.css
│  ├─ ui/                      # UI components for this route
│  │  ├─ board.tsx
│  │  ├─ filter.tsx
│  │  ├─ navbar.tsx
│  │  ├─ pagination.tsx
│  │  ├─ search.tsx
│  │  └─ skeletons.tsx
│  ├─ error.tsx                # Error boundary (client)
│  ├─ layout.tsx               # Root layout (server)
│  ├─ not-found.tsx            # 404 boundary (server)
│  └─ page.tsx                 # Home route (server)
├─ public/
│  └─ screenshots/             # Project screenshots
├─ next.config.ts              # next/image config, etc.
├─ postcss.config.mjs
├─ package.json
├─ pnpm-lock.yaml
├─ tsconfig.json
└─ learn.txt

Screenshots

Screens from the running app:

  • Main page
    • Main page
  • Filters panel
    • Filters
  • Overlay pagination
    • Overlay pagination
  • Responsive design
    • Responsive design
  • Search close button
    • Search close button
  • Loading skeletons
    • Loading skeletons

How to Run

  1. Install dependencies
pnpm install
  1. Start development server
pnpm dev
  1. Open http://localhost:3000

Environment: none required for the public Jikan API.


API Reference

Jikan: Search Anime (getAnimeSearch)

Endpoint: GET https://api.jikan.moe/v4/anime

Query Parameters

Param Type Allowed values / format Description
unapproved boolean flag only (?unapproved) Include user-submitted entries not yet approved by MAL
page integer 1..n Page number
limit integer 1..25 (API default 25) Items per page
q string any Search query (title text)
type string tv, movie, ova, special, ona, music, cm, pv, tv_special Filter by anime type
score number 0..10 Exact score
min_score number 0..10 Minimum score
max_score number 0..10 Maximum score
status string airing, complete, upcoming Airing status
rating string g, pg, pg13, r17, r, rx Audience rating (G, PG, PG-13, R-17, R+, Rx)
sfw boolean true/false Exclude adult entries
genres string comma-separated IDs (e.g., 1,2,3) Include these genres
genres_exclude string comma-separated IDs Exclude these genres
order_by string mal_id, title, start_date, end_date, episodes, score, scored_by, rank, popularity, members, favorites Sort field
sort string desc, asc Sort direction
letter string single letter Title starting letter
producers string comma-separated IDs Filter by producers
start_date string YYYY or YYYY-MM or YYYY-MM-DD Start date filter
end_date string YYYY or YYYY-MM or YYYY-MM-DD End date filter

Example request

GET https://api.jikan.moe/v4/anime?q=death&type=tv&sfw=true&order_by=score&sort=desc&page=1&limit=12

Response shape (simplified)

{
  "pagination": {
    "last_visible_page": 1000,
    "has_next_page": true,
    "items": { "count": 12, "total": 12000, "per_page": 12 }
  },
  "data": [
    {
      "mal_id": 5114,
      "url": "https://myanimelist.net/anime/5114/Fullmetal_Alchemist__Brotherhood",
      "images": {
        "jpg": { "image_url": "https://cdn.myanimelist.net/.../image.jpg" },
        "webp": { "image_url": "https://cdn.myanimelist.net/.../image.webp" }
      },
      "title": "Fullmetal Alchemist: Brotherhood",
      "title_english": "",
      "title_japanese": "鋼の錬金術師",
      "type": "tv",
      "episodes": 64,
      "status": "Finished Airing",
      "rating": "R - 17+",
      "score": 9.1,
      "scored_by": 2000000,
      "rank": 1,
      "popularity": 1,
      "members": 3800000,
      "favorites": 250000,
      "year": 2009,
      "aired": { "from": "2009-04-05", "to": "2010-07-04" },
      "synopsis": "Two brothers search for the Philosopher's Stone...",
      "producers": [{ "mal_id": 23, "name": "Aniplex" }],
      "genres": [{ "mal_id": 1, "name": "Action" }]
    }
  ]
}

APIs and References

  • Next.js Docs (App Router, Data Fetching, Streaming, Error Handling)
  • Jikan (MyAnimeList) API v4: https://api.jikan.moe/v4 (used for anime data)
  • next/image remote patterns to allow cdn.myanimelist.net/images/**

Credits & Disclaimer

  • Styling and layout were refined with the help of AI assistants (including Cursor AI). I iterated on prompts and applied manual adjustments to fit the project’s visual style.
  • Based on learnings from official Next.js tutorials and docs, plus exploration of URL-driven state patterns.
  • Data courtesy of the Jikan API. This project is for learning/demonstration purposes only; no affiliation with MyAnimeList.

If you’re using this as a study reference, I recommend reading through the component files for examples of server vs client components, URLSearchParams-driven state, and pagination/skeleton patterns with streaming.