Skip to content

Latest commit

 

History

History
579 lines (465 loc) · 14.6 KB

ADMIN_GUIDE.md

File metadata and controls

579 lines (465 loc) · 14.6 KB

Modular API System - Admin Guide

🎯 Overview

You can now create endpoints and functions entirely through the Payload Admin UI - no code required! The system supports two modes:

  1. File-based: Import existing functions from your es6Api
  2. Inline Code: Write functions directly in the admin panel

🚀 Quick Start

Step 1: Access Admin Panel

pnpm dev

Visit: http://localhost:3000/admin

Step 2: Create Your First Function via Admin

  1. Navigate to Functions collection
  2. Click Create New
  3. Fill in the form (see examples below)
  4. Save

Step 3: Create a Route

  1. Navigate to Routes collection
  2. Click Create New
  3. Link to your function
  4. Save

That's it! Your endpoint is live immediately at the specified path.


📝 Creating Functions via Admin

Option A: Inline Code (No Files Needed)

Example: Simple Hello World

┌─────────────────────────────────────┐
│ Create New Function                 │
├─────────────────────────────────────┤
│ Name: helloWorld                    │
│ Description: Returns hello message  │
│ Service: other                      │
│ Implementation Type: Inline Code    │
│                                     │
│ Function Code:                      │
│ ┌─────────────────────────────────┐ │
│ │ try {                           │ │
│ │   const name = req.query.name   │ │
│ │   res.json({                    │ │
│ │     message: `Hello ${name}!`   │ │
│ │   })                            │ │
│ │ } catch (error) {               │ │
│ │   res.status(500).json({        │ │
│ │     error: error.message        │ │
│ │   })                            │ │
│ │ }                               │ │
│ └─────────────────────────────────┘ │
│                                     │
│ Response Type: JSON                 │
│ Timeout: 30000                      │
│ Is Async: ✓                         │
│ Active: ✓                           │
│                                     │
│ [Cancel] [Save]                     │
└─────────────────────────────────────┘

Create the Route:

┌─────────────────────────────────────┐
│ Create New Route                    │
├─────────────────────────────────────┤
│ Name: Hello Endpoint                │
│ Path: /api/hello                    │
│ Method: GET                         │
│ Function: helloWorld (dropdown)     │
│ Requires Auth: □                    │
│ Active: ✓                           │
│                                     │
│ [Cancel] [Save]                     │
└─────────────────────────────────────┘

Test it:

curl "http://localhost:3000/api/hello?name=World"
# Response: {"message":"Hello World!"}

Option B: From File (Import es6Api functions)

Example: Knowi Database Query

┌─────────────────────────────────────┐
│ Create New Function                 │
├─────────────────────────────────────┤
│ Name: getKnowiRecords               │
│ Description: Get Knowi DB records   │
│ Service: knowi                      │
│ Implementation Type: From File      │
│                                     │
│ Function File Path:                 │
│ services/knowi/knowiDb.js           │
│                                     │
│ Export Name:                        │
│ getPaginatedKnowiRecords            │
│                                     │
│ Parameters: [Add Parameter]         │
│   - paramName: page                 │
│     paramType: number               │
│     required: □                     │
│     defaultValue: 1                 │
│                                     │
│   - paramName: limit                │
│     paramType: number               │
│     required: □                     │
│     defaultValue: 10                │
│                                     │
│ Response Type: JSON                 │
│ Active: ✓                           │
│                                     │
│ [Cancel] [Save]                     │
└─────────────────────────────────────┘

🔑 Creating API Keys

Example: Create a Developer Key

┌─────────────────────────────────────┐
│ Create New Key                      │
├─────────────────────────────────────┤
│ Name: Developer Key - John          │
│ Key Value: dev_abc123xyz            │
│ Key Type: developer                 │
│ Description: Key for John's apps    │
│                                     │
│ Allowed Routes: (select multiple)   │
│ ☑ GET /api/hello                    │
│ ☑ GET /api/knowi                    │
│ □ POST /api/gptChat                 │
│                                     │
│ Rate Limit:                         │
│ - Window: 900000 (15 min)           │
│ - Max Requests: 100                 │
│                                     │
│ Active: ✓                           │
│                                     │
│ [Cancel] [Save]                     │
└─────────────────────────────────────┘

🌐 Real-World Examples

Example 1: Database Query Endpoint

Function (Inline Code):

try {
  const { collection, limit = 10 } = req.query

  const results = await payload.find({
    collection: collection,
    limit: parseInt(limit),
  })

  res.json({
    success: true,
    data: results.docs,
    total: results.totalDocs,
  })
} catch (error) {
  res.status(500).json({
    success: false,
    error: error.message,
  })
}

Route:

  • Path: /api/query
  • Method: GET
  • Requires Auth: ✓

Usage:

curl "http://localhost:3000/api/query?collection=users&limit=5&key=your-api-key"

Example 2: Create Record Endpoint

Function (Inline Code):

try {
  const { collection, data } = req.body

  if (!collection || !data) {
    return res.status(400).json({
      error: 'collection and data are required',
    })
  }

  const result = await payload.create({
    collection: collection,
    data: data,
  })

  res.json({
    success: true,
    id: result.id,
    data: result,
  })
} catch (error) {
  res.status(500).json({
    success: false,
    error: error.message,
  })
}

Route:

  • Path: /api/create
  • Method: POST
  • Requires Auth: ✓

Usage:

curl -X POST http://localhost:3000/api/create \
  -H "x-api-key: your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "collection": "media",
    "data": {
      "alt": "My image"
    }
  }'

Example 3: GPT Chat Endpoint (From File)

First, copy your es6Api GPT function:

# Copy es6Api services
cp -r /Users/mroberts/Development/dev_JavaScript/personal/es6Api/src/services \
      /Users/mroberts/Development/dev_JavaScript/personal/cctest/api-command/src/

Create Function in Admin:

Name: gptChat
Service: gpt
Implementation Type: From File
Function File Path: services/gpt/gptChat.js
Export Name: gptChat
Response Type: stream
Timeout: 60000

Create Route:

Name: GPT Chat
Path: /api/gpt
Method: POST
Function: gptChat (dropdown)
Requires Auth: ✓
Allowed Keys: [select admin keys]

🎨 Function Code Templates

When you select Inline Code and choose a service, a template is auto-populated!

Knowi Template

// Knowi database query example
const page = parseInt(req.query.page) || 1
const limit = parseInt(req.query.limit) || 10

try {
  // Your Knowi query logic here
  const results = await payload.find({
    collection: 'your-collection',
    page,
    limit
  })

  res.json({
    data: results.docs,
    page: results.page,
    totalPages: results.totalPages
  })
} catch (error) {
  res.status(500).json({ error: error.message })
}

FileMaker Template

// FileMaker operation example
try {
  const data = req.body

  // Your FileMaker logic here
  // Example: Call FileMaker Data API

  res.json({
    status: 'success',
    message: 'Operation completed'
  })
} catch (error) {
  res.status(500).json({ error: error.message })
}

Custom Template

// Custom function example
try {
  // Access request data
  const params = req.query
  const body = req.body

  // Access Payload CMS
  const data = await payload.find({
    collection: 'your-collection'
  })

  // Send response
  res.json({
    status: 'success',
    data: data.docs
  })
} catch (error) {
  res.status(500).json({ error: error.message })
}

🔄 Workflow: Adding a New Endpoint

Complete Example: Weather API Proxy

Step 1: Create Function

  1. Functions → Create New
  2. Name: getWeather
  3. Service: other
  4. Implementation Type: Inline Code
  5. Code:
    try {
      const { city } = req.query
    
      // Call external weather API
      const response = await fetch(
        `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${city}`
      )
      const data = await response.json()
    
      res.json({
        city: city,
        temp: data.current.temp_c,
        condition: data.current.condition.text
      })
    } catch (error) {
      res.status(500).json({ error: error.message })
    }
  6. Save

Step 2: Create Route

  1. Routes → Create New
  2. Name: Weather Endpoint
  3. Path: /api/weather
  4. Method: GET
  5. Function: Select getWeather
  6. Requires Auth: Check ✓
  7. Save

Step 3: Create API Key (if needed)

  1. Keys → Create New
  2. Name: Weather App Key
  3. Key Value: weather_abc123
  4. Key Type: standard
  5. Allowed Routes: Check GET /api/weather
  6. Save

Step 4: Test

curl "http://localhost:3000/api/weather?city=London&key=weather_abc123"

✅ Done! No server restart needed.


🛠️ Available Variables in Function Code

When writing inline code, you have access to:

Request Object (req)

req.query      // URL query parameters
req.body       // POST/PUT body data
req.params     // URL parameters
req.headers    // Request headers
req.method     // HTTP method
req.path       // Request path

Response Object (res)

res.json({ data })           // Send JSON response
res.status(404).json({})     // Set status code
res.send('text')             // Send text
res.redirect('/path')        // Redirect

Payload CMS (payload)

await payload.find({ collection: 'users' })
await payload.findByID({ collection: 'users', id: '123' })
await payload.create({ collection: 'users', data: {} })
await payload.update({ collection: 'users', id: '123', data: {} })
await payload.delete({ collection: 'users', id: '123' })

Built-in Globals

console.log()  // Logging
JSON           // JSON utilities
Math           // Math operations
Date           // Date handling
fetch()        // HTTP requests (if available)

📊 Monitoring & Management

View API Key Usage

  1. Navigate to Keys collection
  2. Click on any key
  3. View:
    • Last Used At
    • Usage Count
    • Associated User

Disable a Route Temporarily

  1. Navigate to Routes collection
  2. Find the route
  3. Uncheck Active
  4. Save

The route is immediately unavailable!

Update Function Code

  1. Navigate to Functions collection
  2. Find your function
  3. Edit the Function Code field
  4. Save

Changes take effect immediately (cache is cleared automatically).


🔐 Security Best Practices

For Inline Code:

  • ✅ Always validate input
  • ✅ Use try/catch blocks
  • ✅ Check for required parameters
  • ✅ Sanitize user data
  • ❌ Don't expose sensitive env vars directly
  • ❌ Don't execute user-provided code

For API Keys:

  • ✅ Use descriptive names
  • ✅ Set expiration dates
  • ✅ Limit routes per key
  • ✅ Set appropriate rate limits
  • ✅ Use different key types for different access levels

For Routes:

  • ✅ Always require auth for sensitive operations
  • ✅ Use appropriate HTTP methods (GET for read, POST for create, etc.)
  • ✅ Set specific allowed keys for restricted routes

🐛 Troubleshooting

"Function execution failed"

  • Check function code for syntax errors
  • Check console logs for detailed error
  • Ensure all required variables are defined

"API key is required"

  • Add ?key=your-key to URL or
  • Add x-api-key: your-key header

"Route not found"

  • Check route is Active
  • Verify path matches exactly
  • Check method (GET/POST/etc) matches

Changes not taking effect

  • Hard refresh admin page (Cmd+Shift+R)
  • Check function is marked Active
  • Check route is marked Active

📈 Advanced: Importing All es6Api Functions

To migrate all your existing es6Api functions at once:

# 1. Copy all source files
cp -r /Users/mroberts/Development/dev_JavaScript/personal/es6Api/src/services \
      /Users/mroberts/Development/dev_JavaScript/personal/cctest/api-command/src/

cp -r /Users/mroberts/Development/dev_JavaScript/personal/es6Api/src/routes \
      /Users/mroberts/Development/dev_JavaScript/personal/cctest/api-command/src/

# 2. Run the seed script
pnpm tsx src/scripts/seedApiData.ts

This will create:

  • ✅ All functions from es6Api
  • ✅ All routes
  • ✅ API keys
  • ✅ Endpoints

Then manage everything via admin UI!


🎓 Next Steps

  1. Copy your es6Api services to this project
  2. Create functions via admin for each service
  3. Create routes linking to functions
  4. Create API keys for different access levels
  5. Test endpoints with curl or Postman
  6. Monitor usage through Keys collection

Everything is now manageable through the UI! 🎉

No code changes needed - just point and click in the admin panel.