Skip to content

Generic Open Data Backend - REST API dengan Next.js, JWT Auth & Flexible JSON Storage

License

Notifications You must be signed in to change notification settings

JabesNelma/data-hub-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Data Hub API

A Generic Open Data Backend

A production-ready, open-source REST API that can store and serve ANY type of data using categories and flexible JSON structures.

MIT License Next.js TypeScript Demo

🌐 Live Demo: https://data-hub-api.vercel.app

⚠️ PENTING / IMPORTANT: Live demo di Vercel hanya menampilkan halaman dokumentasi frontend saja. API endpoint (CRUD, Auth, dll) TIDAK bisa digunakan di Vercel karena project ini menggunakan SQLite (file-based database) yang tidak kompatibel dengan Vercel serverless (read-only filesystem).

Untuk testing API secara penuh, silakan clone repository dan jalankan secara lokal. Lihat bagian Getting Started dan Local Testing Guide.


πŸ“– Overview

Data Hub API is a generic open data backend designed to store and serve ANY type of data using categories and flexible JSON structures. The API is designed to be consumed by:

  • Web applications
  • Mobile applications
  • Dashboards
  • External services

This project provides:

  • RESTful API with Next.js App Router
  • JWT Authentication with access/refresh tokens
  • Role-based access control (admin/user roles)
  • Flexible JSON data storage
  • Developer documentation frontend

✨ Features

πŸ” Authentication & Security

  • JWT-based authentication with access and refresh tokens
  • Role-based access control (admin/user)
  • bcrypt password hashing
  • Public read access for all data
  • Admin-only write operations

πŸ—„οΈ Data Management

  • Flexible JSON-based data storage
  • Categorization system
  • Data type classification
  • Full CRUD operations for admin users

πŸš€ API Features

  • RESTful API design
  • Consistent response format
  • JSON content storage
  • Query parameter filtering
  • Comprehensive error handling

πŸ“š Documentation

  • Interactive API documentation
  • Example requests (curl and fetch)
  • Clear authentication flow
  • Developer-friendly guides

πŸ› οΈ Tech Stack

Backend

  • Next.js 16 - React framework with App Router
  • TypeScript 5 - Type-safe development
  • Prisma ORM - Database toolkit
  • SQLite - Database (production-ready for PostgreSQL migration)
  • jose - JWT token generation/verification
  • bcrypt - Password hashing

Frontend Documentation

  • Next.js 16 with App Router
  • TypeScript 5
  • Tailwind CSS 4
  • shadcn/ui components
  • Lucide icons

πŸ“Š Database Schema

Tables

users

User accounts with authentication support

  • id - Primary key
  • email - Unique email address
  • passwordHash - Bcrypt hashed password
  • role - User role (admin/user)
  • isActive - Account status
  • createdAt - Creation timestamp
  • updatedAt - Update timestamp

categories

Categories for organizing data

  • id - Primary key
  • name - Category name
  • description - Category description
  • createdAt - Creation timestamp
  • updatedAt - Update timestamp

dataTypes

Data type classification

  • id - Primary key
  • name - Type name
  • description - Type description
  • createdAt - Creation timestamp
  • updatedAt - Update timestamp

dataEntries

Flexible data entries with JSON content

  • id - Primary key
  • categoryId - Foreign key to categories
  • typeId - Foreign key to dataTypes
  • title - Entry title
  • content - JSON content (stored as TEXT)
  • source - Data source
  • createdAt - Creation timestamp
  • updatedAt - Update timestamp

πŸ”‘ API Endpoints

Authentication

POST /api/auth/login

Authenticate with username and password.

Request Body:

{
  "username": "JabesNelma",
  "password": "your-password"
}

Response:

{
  "success": true,
  "data": {
    "user": {
      "id": "user-id",
      "username": "JabesNelma",
      "role": "admin"
    },
    "accessToken": "jwt-access-token",
    "refreshToken": "jwt-refresh-token"
  },
  "message": "Login successful"
}

POST /api/auth/refresh

Refresh access token using refresh token.

Request Body:

{
  "refreshToken": "jwt-refresh-token"
}

Response:

{
  "success": true,
  "data": {
    "accessToken": "new-jwt-access-token"
  },
  "message": "Token refreshed successfully"
}

POST /api/auth/logout

Logout current session.

Response:

{
  "success": true,
  "message": "Logout successful"
}

Data Management

GET /api/data

Get all data entries (public read access).

Query Parameters:

  • categoryId (optional) - Filter by category
  • typeId (optional) - Filter by type

Response:

{
  "success": true,
  "data": [
    {
      "id": "entry-id",
      "categoryId": "category-id",
      "typeId": "type-id",
      "title": "Entry Title",
      "content": { "key": "value" },
      "source": "source",
      "createdAt": "2025-01-01T00:00:00Z",
      "updatedAt": "2025-01-01T00:00:00Z",
      "category": { "id": "...", "name": "..." },
      "type": { "id": "...", "name": "..." }
    }
  ],
  "message": "Data entries retrieved successfully"
}

GET /api/data/:id

Get data entry by ID (public read access).

Response:

{
  "success": true,
  "data": {
    "id": "entry-id",
    "categoryId": "category-id",
    "typeId": "type-id",
    "title": "Entry Title",
    "content": { "key": "value" },
    "source": "source",
    "createdAt": "2025-01-01T00:00:00Z",
    "updatedAt": "2025-01-01T00:00:00Z",
    "category": { "id": "...", "name": "..." },
    "type": { "id": "...", "name": "..." }
  },
  "message": "Data entry retrieved successfully"
}

POST /api/data (Admin Only)

Create new data entry.

Request Headers:

Authorization: Bearer {access-token}

Request Body:

{
  "categoryId": "category-id",
  "typeId": "type-id",
  "title": "Entry Title",
  "content": { "key": "value", "nested": { "data": "here" } },
  "source": "optional-source"
}

Response:

{
  "success": true,
  "data": {
    "id": "entry-id",
    "categoryId": "category-id",
    "typeId": "type-id",
    "title": "Entry Title",
    "content": { "key": "value" },
    "source": "optional-source",
    "createdAt": "2025-01-01T00:00:00Z",
    "updatedAt": "2025-01-01T00:00:00Z",
    "category": { "id": "...", "name": "..." },
    "type": { "id": "...", "name": "..." }
  },
  "message": "Data entry created successfully"
}

PUT /api/data/:id (Admin Only)

Update data entry.

Request Headers:

Authorization: Bearer {access-token}

Request Body:

{
  "categoryId": "category-id",
  "typeId": "type-id",
  "title": "Updated Title",
  "content": { "key": "updated-value" },
  "source": "updated-source"
}

Response:

{
  "success": true,
  "data": {
    "id": "entry-id",
    ...
  },
  "message": "Data entry updated successfully"
}

DELETE /api/data/:id (Admin Only)

Delete data entry.

Request Headers:

Authorization: Bearer {access-token}

Response:

{
  "success": true,
  "message": "Data entry deleted successfully"
}

Categories & Types

GET /api/categories

Get all categories (public read access).

Response:

{
  "success": true,
  "data": [
    {
      "id": "category-id",
      "name": "General",
      "description": "General data entries",
      "createdAt": "2025-01-01T00:00:00Z",
      "updatedAt": "2025-01-01T00:00:00Z",
      "_count": { "dataEntries": 10 }
    }
  ],
  "message": "Categories retrieved successfully"
}

GET /api/types

Get all data types (public read access).

Response:

{
  "success": true,
  "data": [
    {
      "id": "type-id",
      "name": "JSON",
      "description": "JSON formatted data",
      "createdAt": "2025-01-01T00:00:00Z",
      "updatedAt": "2025-01-01T00:00:00Z",
      "_count": { "dataEntries": 15 }
    }
  ],
  "message": "Data types retrieved successfully"
}

Admin Setup

POST /api/admin/seed

Create initial admin user and default data.

Request Body:

{
  "username": "JabesNelma",
  "password": "secure-password",
  "seedKey": "admin-setup-key"
}

Response:

{
  "success": true,
  "data": {
    "user": { "id": "...", "username": "JabesNelma", "role": "admin" },
    "categories": [...],
    "types": [...]
  },
  "message": "Admin user and default data seeded successfully"
}

πŸš€ Getting Started

Prerequisites

  • Node.js 18+
  • Bun (recommended) or npm/yarn

Installation

  1. Clone the repository

    git clone https://github.com/your-username/data-hub-api.git
    cd data-hub-api
  2. Install dependencies

    bun install
  3. Configure environment variables

    cp .env.example .env

    Edit .env and update the values:

    DATABASE_URL="file:./db/custom.db"
    JWT_SECRET="your-secret-key-min-32-chars"
    JWT_REFRESH_SECRET="your-refresh-secret-key-min-32-chars"
    SEED_KEY="admin-setup-key"
    NODE_ENV="development"

    IMPORTANT: Generate strong secrets for production!

  4. Set up the database

    bun run db:push
  5. Create admin user

    curl -X POST http://localhost:3000/api/admin/seed \
      -H "Content-Type: application/json" \
      -d '{
        "username": "JabesNelma",
        "password": "your-secure-password",
        "seedKey": "admin-setup-key"
      }'
  6. Start the development server

    bun run dev
  7. Access the application


πŸ“ Example Requests

Login with curl

curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "JabesNelma",
    "password": "your-password"
  }'

Get data with curl

# Get all data
curl http://localhost:3000/api/data

# Get data with filters
curl "http://localhost:3000/api/data?categoryId=category-id&typeId=type-id"

# Get specific entry
curl http://localhost:3000/api/data/entry-id

Create data with curl

curl -X POST http://localhost:3000/api/data \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{
    "categoryId": "category-id",
    "typeId": "type-id",
    "title": "My Data Entry",
    "content": {
      "key": "value",
      "nested": {
        "data": "here"
      }
    },
    "source": "my-app"
  }'

Fetch data with JavaScript

// Get all data (public)
const response = await fetch('http://localhost:3000/api/data');
const { success, data, message } = await response.json();

if (success) {
  console.log('Data entries:', data);
}

// Create data entry (requires admin token)
const createResponse = await fetch('http://localhost:3000/api/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
  },
  body: JSON.stringify({
    categoryId: 'category-id',
    typeId: 'type-id',
    title: 'New Entry',
    content: { key: 'value' },
    source: 'my-app'
  })
});
const result = await createResponse.json();

πŸ“¦ Project Structure

data-hub-api/
β”œβ”€β”€ prisma/
β”‚   β”œβ”€β”€ schema.prisma       # Database schema
β”‚   └── migrations/         # Database migrations
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ api/
β”‚   β”‚   β”‚   β”œβ”€β”€ auth/       # Authentication routes
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ login/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ refresh/
β”‚   β”‚   β”‚   β”‚   └── logout/
β”‚   β”‚   β”‚   β”œβ”€β”€ data/       # Data management routes
β”‚   β”‚   β”‚   β”‚   └── [id]/
β”‚   β”‚   β”‚   β”œβ”€β”€ categories/
β”‚   β”‚   β”‚   β”œβ”€β”€ types/
β”‚   β”‚   β”‚   └── admin/
β”‚   β”‚   β”‚       └── seed/
β”‚   β”‚   β”œβ”€β”€ page.tsx        # Documentation landing page
β”‚   β”‚   └── layout.tsx
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   └── ui/             # shadcn/ui components
β”‚   └── lib/
β”‚       β”œβ”€β”€ db.ts           # Prisma client
β”‚       β”œβ”€β”€ auth.ts         # JWT utilities
β”‚       └── api-auth.ts     # API authentication middleware
β”œβ”€β”€ db/
β”‚   └── custom.db           # SQLite database file
β”œβ”€β”€ .env.example            # Environment variables template
β”œβ”€β”€ LICENSE                 # MIT License
β”œβ”€β”€ README.md               # This file
└── package.json

πŸ”’ Authentication & Authorization

Token Types

Access Token

  • Lifetime: 15 minutes
  • Usage: API requests
  • Header: Authorization: Bearer {token}

Refresh Token

  • Lifetime: 7 days
  • Usage: Get new access tokens
  • More secure, long-lived

Authentication Flow

  1. Send POST request to /api/auth/login with email and password
  2. Receive access token and refresh token in response
  3. Include access token in Authorization header: Bearer {token}
  4. When access token expires, use refresh token to get a new one
  5. Include new access token in subsequent requests

Access Control

  • Public Access: GET requests to /api/data, /api/categories, /api/types
  • Admin Required: POST, PUT, DELETE requests to /api/data/*

🚒 Deployment

Deploy to Vercel

  1. Push your code to GitHub
  2. Connect repository to Vercel
  3. Configure environment variables in Vercel dashboard:
    • DATABASE_URL
    • JWT_SECRET
    • JWT_REFRESH_SECRET
    • SEED_KEY
    • NODE_ENV (set to production)
  4. Deploy

Deploy to Other Platforms

This project can be deployed to any platform that supports Next.js:

  • Vercel (recommended)
  • Netlify
  • Railway
  • Render
  • Self-hosted with Docker

Environment Variables

Make sure to set these in your production environment:

DATABASE_URL="your-database-url"
JWT_SECRET="strong-secret-at-least-32-characters"
JWT_REFRESH_SECRET="another-strong-secret-at-least-32-characters"
SEED_KEY="unique-seed-key-for-initial-setup"
NODE_ENV="production"

IMPORTANT: Use strong, randomly generated secrets in production!


πŸ§ͺ Development

Running Tests

bun run lint

Database Management

# Push schema changes to database
bun run db:push

# Open Prisma Studio (database GUI)
bun run db:studio

# Generate Prisma Client
bun run db:generate

Code Quality

# Lint code
bun run lint

# Type check
bun run type-check

πŸ§ͺ Local Testing Guide

Kenapa harus lokal? Project ini menggunakan SQLite (file-based database). Vercel menggunakan serverless functions dengan filesystem read-only, sehingga database tidak bisa dibuat/ditulis. Untuk testing API, wajib jalankan di lokal.

Step 1: Clone & Setup

git clone https://github.com/JabesNelma/data-hub-api.git
cd data-hub-api
npm install
cp .env.example .env
npm run db:push
npm run dev

Step 2: Seed Admin User

curl -s -X POST http://localhost:3000/api/admin/seed \
  -H "Content-Type: application/json" \
  -d '{
    "username": "JabesNelma",
    "password": "SecurePassword123!",
    "seedKey": "admin-setup-key"
  }'

Step 3: Login & Dapatkan Token

curl -s -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "JabesNelma",
    "password": "SecurePassword123!"
  }'

Simpan accessToken dari response untuk digunakan di request selanjutnya.

Step 4: Test Semua Endpoint

# GET categories (public)
curl -s http://localhost:3000/api/categories

# GET types (public)
curl -s http://localhost:3000/api/types

# GET all data (public)
curl -s http://localhost:3000/api/data

# POST create data (admin only)
curl -s -X POST http://localhost:3000/api/data \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{
    "categoryId": "CATEGORY_ID",
    "typeId": "TYPE_ID",
    "title": "Data Penduduk Jakarta",
    "content": {
      "provinsi": "DKI Jakarta",
      "populasi": 10500000,
      "tahun": 2026
    },
    "source": "BPS Indonesia"
  }'

# GET data by ID (public)
curl -s http://localhost:3000/api/data/DATA_ID

# PUT update data (admin only)
curl -s -X PUT http://localhost:3000/api/data/DATA_ID \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -d '{
    "title": "Updated Title",
    "content": { "key": "updated-value" }
  }'

# DELETE data (admin only)
curl -s -X DELETE http://localhost:3000/api/data/DATA_ID \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

# Refresh token
curl -s -X POST http://localhost:3000/api/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{ "refreshToken": "YOUR_REFRESH_TOKEN" }'

# Logout
curl -s -X POST http://localhost:3000/api/auth/logout \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

βœ… Hasil Testing Lokal (Verified)

Semua endpoint telah diuji dan berjalan dengan baik secara lokal:

# Endpoint Method Status Keterangan
1 /api/admin/seed POST βœ… Pass Admin user + categories + types berhasil dibuat
2 /api/auth/login POST βœ… Pass JWT access token & refresh token didapat
3 /api/categories GET βœ… Pass 3 categories: General, Documentation, API
4 /api/types GET βœ… Pass 3 types: JSON, Text, Structured
5 /api/data GET βœ… Pass List semua data entries
6 /api/data POST βœ… Pass Data entry baru berhasil dibuat
7 /api/data/:id GET βœ… Pass Get data by ID berhasil
8 /api/data/:id PUT βœ… Pass Data berhasil diupdate
9 /api/data/:id DELETE βœ… Pass Data berhasil dihapus
10 /api/auth/refresh POST βœ… Pass Access token baru didapat
11 /api/auth/logout POST βœ… Pass Logout berhasil

⚠️ Catatan Penting tentang Deployment

Platform Frontend Docs API (SQLite) Keterangan
Localhost βœ… βœ… Full functionality β€” recommended untuk testing
Vercel βœ… ❌ Hanya frontend docs, API error karena SQLite read-only
Railway βœ… βœ… Support persistent disk β€” bisa pakai SQLite
VPS / Docker βœ… βœ… Full control β€” recommended untuk production

Tips: Jika ingin deploy API ke production, pertimbangkan migrasi database ke PostgreSQL atau MySQL dan deploy ke platform yang support persistent storage seperti Railway, Render, atau VPS sendiri.


πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


🀝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

πŸ“ž Support

For issues, questions, or contributions:

  • Open an issue on GitHub
  • Check the documentation at http://localhost:3000
  • Review the API endpoints above

🌟 Acknowledgments


Made with ❀️ for the developer community


Data Hub API - Generic Open Data Backend

🌐 Live Demo (Frontend Only): https://data-hub-api.vercel.app

πŸ“¦ Repository: https://github.com/JabesNelma/data-hub-api

Created by Jabes Nelma

Junior Full Stack Developer β€’ MIT License β€’ Open Source

About

Generic Open Data Backend - REST API dengan Next.js, JWT Auth & Flexible JSON Storage

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published