we0-cms-supabase-api
Version:
A CMS API package for Next.js applications with Supabase and dynamic table management
443 lines (349 loc) • 9.77 kB
Markdown
# we0-cms-supabase-api
A powerful CMS API package for Next.js applications with dynamic table management and Supabase support.
## Features
- 🚀 Dynamic table creation and management
- 📊 RESTful API for models and data operations
- 🔧 TypeScript support with full type definitions
- 💾 Supabase backend with real-time capabilities
- 🎯 Easy integration with Next.js API routes
- 📝 Comprehensive CRUD operations
- 🔐 Built-in authentication and security with Supabase
- ⚡ Real-time data synchronization
## Installation
```bash
npm install we0-cms-supabase-api
# or
yarn add we0-cms-supabase-api
# or
pnpm add we0-cms-supabase-api
```
### Peer Dependencies
Make sure you have the following peer dependencies installed:
```bash
npm install next /supabase-js
```
## Quick Start
### 1. Supabase Configuration
First, initialize the Supabase connection in your Next.js app:
```typescript
// lib/cms-config.ts
import {
executeSupabaseSetup,
getSupabaseSetupSQL,
initializeSupabase,
SupabaseConfig,
} from "we0-cms-supabase-api"
const supabaseConfig: SupabaseConfig = {
url: process.env.NEXT_PUBLIC_SUPABASE_URL!,
key: process.env.SUPABASE_SERVICE_ROLE_KEY!, // Use service role key for server-side operations
schema: "public", // Optional, defaults to 'public'
}
// Initialize Supabase connection
initializeSupabase(supabaseConfig)
// 🆕 自动设置数据库(推荐)
async function setupDatabase() {
const setupSuccess = await executeSupabaseSetup()
if (!setupSuccess) {
// 如果自动设置失败,获取 SQL 脚本手动执行
const setupSQL = getSupabaseSetupSQL()
console.log("请在 Supabase SQL 编辑器中执行以下 SQL:")
console.log(setupSQL)
}
}
// 在应用启动时调用
setupDatabase()
```
### 2. Supabase 数据库设置
#### 🆕 自动设置(推荐)
现在你可以通过代码自动检查和设置 Supabase 数据库:
```typescript
import { executeSupabaseSetup, getSupabaseSetupSQL } from "we0-cms-supabase-api"
// 自动设置
const success = await executeSupabaseSetup()
if (!success) {
// 获取完整的 SQL 脚本
const sql = getSupabaseSetupSQL()
// 复制到 Supabase SQL 编辑器执行
}
```
#### 手动设置(备选方案)
如果自动设置失败,你需要在 Supabase SQL 编辑器中手动执行以下 SQL 函数:
You need to create the following SQL functions in your Supabase database for the CMS to work properly:
```sql
-- Function to execute SQL queries
CREATE OR REPLACE FUNCTION execute_sql(sql_query text)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
result json;
BEGIN
EXECUTE sql_query;
GET DIAGNOSTICS result = ROW_COUNT;
RETURN json_build_object('success', true, 'rows_affected', result);
EXCEPTION
WHEN OTHERS THEN
RETURN json_build_object('success', false, 'error', SQLERRM);
END;
$$;
-- Function to execute SQL with parameters
CREATE OR REPLACE FUNCTION execute_sql_with_params(sql_query text, params json)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
result json;
BEGIN
-- This is a simplified version - in production you'd want proper parameter binding
EXECUTE sql_query;
GET DIAGNOSTICS result = ROW_COUNT;
RETURN json_build_object('success', true, 'rows_affected', result);
EXCEPTION
WHEN OTHERS THEN
RETURN json_build_object('success', false, 'error', SQLERRM);
END;
$$;
-- Function to check if table exists
CREATE OR REPLACE FUNCTION check_table_exists(table_name text)
RETURNS boolean
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
BEGIN
RETURN EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = $1
);
END;
$$;
-- Function to get table structure
CREATE OR REPLACE FUNCTION get_table_structure(table_name text)
RETURNS json
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
result json;
BEGIN
SELECT json_agg(
json_build_object(
'column_name', column_name,
'data_type', data_type,
'is_nullable', is_nullable,
'column_default', column_default
)
) INTO result
FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = $1;
RETURN result;
END;
$$;
```
### 3. Create API Routes
#### Models Management API
Create `app/api/cms/models/route.ts`:
```typescript
import { createModelRoute } from "we0-cms-supabase-api"
export const { GET, POST, PUT, DELETE } = createModelRoute()
```
#### Dynamic Data Management API
Create `app/api/cms/data/[tableName]/route.ts`:
```typescript
import { createDynamicDataRoute } from "we0-cms-supabase-api"
export const { GET, POST, PUT, DELETE } = createDynamicDataRoute()
```
#### Alternative: One-liner Setup
Use the convenience function to create all routes at once:
```typescript
// app/api/cms/models/route.ts
import { createCmsRoutes } from "we0-cms-supabase-api"
const routes = createCmsRoutes()
export const { GET, POST, PUT, DELETE } = routes.models
```
```typescript
// app/api/cms/data/[tableName]/route.ts
import { createCmsRoutes } from "we0-cms-supabase-api"
const routes = createCmsRoutes()
export const { GET, POST, PUT, DELETE } = routes.data
```
## API Usage
### Models API
#### GET `/api/cms/models` - Get all models
```bash
curl "http://localhost:3000/api/cms/models?page=1&limit=10&name=user"
```
#### POST `/api/cms/models` - Create a new model
```bash
curl -X POST "http://localhost:3000/api/cms/models" \
-H "Content-Type: application/json" \
-d '{
"name": "用户模型",
"table_name": "users",
"json_schema": {
"fields": [
{
"name": "name",
"type": "string",
"required": true,
"maxLength": 100,
"comment": "用户姓名"
},
{
"name": "email",
"type": "email",
"unique": true,
"required": true,
"comment": "用户邮箱"
},
{
"name": "age",
"type": "integer",
"comment": "年龄"
}
]
}
}'
```
#### PUT `/api/cms/models` - Update a model
```bash
curl -X PUT "http://localhost:3000/api/cms/models" \
-H "Content-Type: application/json" \
-d '{
"id": 1,
"name": "更新的用户模型"
}'
```
#### DELETE `/api/cms/models?id=1` - Delete a model
```bash
curl -X DELETE "http://localhost:3000/api/cms/models?id=1"
```
### Data API
#### GET `/api/cms/data/users` - Get table data
```bash
curl "http://localhost:3000/api/cms/data/users?page=1&limit=10&search=john"
```
#### POST `/api/cms/data/users` - Create new data
```bash
curl -X POST "http://localhost:3000/api/cms/data/users" \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"age": 30
}'
```
#### PUT `/api/cms/data/users` - Update data
```bash
curl -X PUT "http://localhost:3000/api/cms/data/users" \
-H "Content-Type: application/json" \
-d '{
"id": 1,
"name": "John Smith",
"age": 31
}'
```
#### DELETE `/api/cms/data/users?id=1` - Delete data
```bash
curl -X DELETE "http://localhost:3000/api/cms/data/users?id=1"
```
## Advanced Usage
### Custom Service Usage
```typescript
import {
getCmsModelService,
getDynamicTableService,
initializeSupabase,
SupabaseConfig,
} from "we0-cms-supabase-api"
// Initialize Supabase
const supabaseConfig: SupabaseConfig = {
url: process.env.NEXT_PUBLIC_SUPABASE_URL!,
key: process.env.SUPABASE_SERVICE_ROLE_KEY!,
}
initializeSupabase(supabaseConfig)
// Use the dynamic table service directly
const tableService = getDynamicTableService()
// Create a custom table
await tableService.createTable("custom_table", {
fields: [
{ name: "title", type: "string", required: true },
{ name: "content", type: "text" },
],
})
// Use the CMS model service directly
const cmsModelService = getCmsModelService()
const models = await cmsModelService.findAll()
```
### Type Definitions
```typescript
import type {
ApiResponse,
CmsModelAttributes,
JsonSchema,
PaginatedResponse,
SchemaField,
SupabaseConfig,
} from "we0-cms-supabase-api"
// Define your schema
const userSchema: JsonSchema = {
fields: [
{
name: "username",
type: "string",
required: true,
unique: true,
maxLength: 50,
},
{
name: "profile",
type: "json",
},
],
}
```
## Environment Variables
Create a `.env.local` file in your project root:
```env
# Supabase Configuration
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key
# Optional: Custom schema (defaults to 'public')
SUPABASE_SCHEMA=public
```
You can find these values in your Supabase project dashboard:
- `NEXT_PUBLIC_SUPABASE_URL`: Project Settings > API > Project URL
- `SUPABASE_SERVICE_ROLE_KEY`: Project Settings > API > service_role key (keep this secret!)
## Field Types
Supported field types for JSON schema:
- `string` - Variable length string
- `text` - Long text
- `integer` - Integer number
- `float` - Floating point number
- `boolean` - True/false value
- `date` - Date only
- `datetime` - Date and time
- `json` - JSON object
- `email` - Email string (validated as string)
## Error Handling
All API responses follow a consistent format:
```typescript
interface ApiResponse<T = any> {
success: boolean
message?: string
data?: T
error?: string
}
```
## Contributing
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
MIT
## Support
For support, please open an issue on the GitHub repository or contact the maintainers.