Skip to content

tm1981/tmdb-caching-api

Repository files navigation

TMDB Data Caching Service

A Next.js 16 service that caches TMDB movie and TV show data in PostgreSQL, MySQL, or MariaDB, providing a fast local API with lazy sync and admin dashboard.

Tech Stack

  • Next.js 16 with App Router
  • PostgreSQL, MySQL, or MariaDB for data storage
  • Prisma 7 as ORM
  • next-auth v4 for admin authentication
  • shadcn/ui + Tailwind CSS 4 for admin UI

Prerequisites

  • Node.js 20+
  • PostgreSQL 14+, MySQL 8+, or MariaDB 10.6+
  • TMDB API key from themoviedb.org

Setup

1. Choose and create the database

Choose the database type before setup. The selected type is fixed for that installation; changing it later means setting up a new database or migrating data yourself.

Create an empty database named tmdb_service in one of:

# PostgreSQL
createdb tmdb_service

# MySQL
mysql -u root -p -e "CREATE DATABASE tmdb_service CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# MariaDB
mariadb -u root -p -e "CREATE DATABASE tmdb_service CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

2. Clone and install dependencies

cd tmdb-service
npm install

3. Configure environment variables

Copy .env.example to .env and fill in your values:

DATABASE_PROVIDER=mysql
DATABASE_URL=mysql://user:password@host:3306/tmdb_service
TMDB_API_KEY=your_tmdb_api_key_here
NEXTAUTH_SECRET=your_random_secret_here
NEXTAUTH_URL=http://localhost:3000
ADMIN_USERNAME=admin@example.com
ADMIN_PASSWORD=your_secure_password
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=your_smtp_username
SMTP_PASSWORD=your_smtp_password
SMTP_FROM="TMDB Service <no-reply@example.com>"

Database URL examples:

# PostgreSQL
DATABASE_PROVIDER=postgresql
DATABASE_URL=postgresql://user:password@host:5432/tmdb_service

# MySQL
DATABASE_PROVIDER=mysql
DATABASE_URL=mysql://user:password@host:3306/tmdb_service

# MariaDB
DATABASE_PROVIDER=mariadb
DATABASE_URL=mysql://user:password@host:3306/tmdb_service

DATABASE_PROVIDER must match DATABASE_URL before running Prisma commands or building the app. For MySQL, use DATABASE_PROVIDER=mysql and a mysql://... URL.

4. Set up the database

For a new local/dev database, db push is the simplest setup path for any provider:

# Generate Prisma Client for your selected database
npm run db:generate

# Create/update tables
npm run db:push

# Seed with admin user and default API key
npm run db:seed

Database Migrations

Prisma migration SQL is provider-specific. Do not run PostgreSQL migrations against MySQL/MariaDB, or MySQL migrations against PostgreSQL.

This repository currently has PostgreSQL migration files in prisma/migrations/:

cat prisma/migrations/migration_lock.toml
# provider = "postgresql"

PostgreSQL production

Use the checked-in migrations:

DATABASE_PROVIDER=postgresql npx prisma migrate deploy
npm run build
pm2 restart tmdb

Create a new PostgreSQL migration after schema changes:

DATABASE_PROVIDER=postgresql npx prisma migrate dev --name describe_change

Commit the generated prisma/migrations/* files.

MySQL / MariaDB production

The checked-in migrations are not MySQL-compatible. For the current MySQL/MariaDB install, use:

DATABASE_PROVIDER=mysql npx prisma db push
npm run build
pm2 restart tmdb

Use DATABASE_PROVIDER=mariadb for MariaDB if your .env uses that provider.

To use real MySQL/MariaDB migrations later, create a separate MySQL/MariaDB migration history from prisma/schema.mysql.prisma on a clean database, then commit that provider-specific migration set. Do not mix it with the PostgreSQL migration folder.

5. Run the development server

npm run dev

The app will be available at http://localhost:3000.

6. Login to admin dashboard

Go to http://localhost:3000/login and use the admin credentials you set in .env.

Admin Dashboard

After login, the admin dashboard provides:

  • Movies - Browse, search, and manage cached movies
  • TV Shows - Browse, search, and manage cached TV shows
  • Sync - Trigger bulk syncs (trending movies/TV, top rated)
  • API Keys - Create, manage, and revoke API keys

API Endpoints

All API endpoints require the x-api-key header. Rate limit: 60 requests per minute per key.

For TMDB-compatible content mirroring, use /api/v1/tmdb/{tmdb_path}. It forwards public TMDB content GET endpoints, caches successful JSON responses, and keeps TMDB's response shape. See docs/api.md.

Movies

Method Endpoint Description
GET /api/v1/movies List all movies with pagination
GET /api/v1/movies/:id Get movie details by TMDB ID (lazy syncs if missing)

Query parameters for /api/v1/movies:

Param Type Default Description
page int 1 Page number
limit int 20 Items per page
q string - Search by title

TV Shows

Method Endpoint Description
GET /api/v1/tv List all TV shows with pagination
GET /api/v1/tv/:id Get TV show details by TMDB ID (lazy syncs if missing)

Query parameters for /api/v1/tv:

Param Type Default Description
page int 1 Page number
limit int 20 Items per page
q string - Search by name

Search

Method Endpoint Description
GET /api/v1/search?q=term Search both movies and TV shows

Example Requests

# Get movies list
curl -H "x-api-key: your_api_key" http://localhost:3000/api/v1/movies

# Get movie by TMDB ID (lazy syncs if not cached)
curl -H "x-api-key: your_api_key" http://localhost:3000/api/v1/movies/278

# Search movies and TV shows
curl -H "x-api-key: your_api_key" "http://localhost:3000/api/v1/search?q=matrix"

# Paginate with search
curl -H "x-api-key: your_api_key" "http://localhost:3000/api/v1/movies?page=2&limit=10&q=action"

Response Format

List endpoints return:

{
  "data": [...],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "totalPages": 8
  }
}

Detail endpoints return TMDB-compatible JSON:

{
  "id": 278,
  "title": "The Shawshank Redemption",
  "overview": "...",
  "poster_path": "/...",
  "backdrop_path": "/...",
  "credits": { "cast": [], "crew": [] },
  "videos": { "results": [] }
}

Search endpoint returns:

{
  "data": {
    "movies": [...],
    "tvShows": [...]
  }
}

Production Build

npm run db:generate
npm run build
PORT=3000 npm run start

The app uses the normal Next.js production server via next start. Set NEXTAUTH_URL to the public HTTPS domain in production.

Lazy Sync

When a client requests a movie or TV show by TMDB ID that isn't in the local database, the service automatically fetches it from TMDB, stores it, and returns it. This eliminates the need for pre-populating the database.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors