208 lines
7.6 KiB
Org Mode
208 lines
7.6 KiB
Org Mode
#+TITLE: API Endpoint Refactoring - 2025-10-08
|
|
#+AUTHOR: Cascade AI Assistant
|
|
#+DATE: 2025-10-08
|
|
|
|
* Overview
|
|
|
|
Successfully refactored all API endpoints to use Radiance's built-in =define-api= macro following the framework's best practices and conventions.
|
|
|
|
** What Changed
|
|
- ✅ All API endpoints now use =define-api= (15 endpoints converted)
|
|
- ✅ Web pages still use =define-page= (correct usage for rendering HTML)
|
|
- ✅ Static file serving still uses =define-page= (correct usage)
|
|
|
|
** Separation of Concerns
|
|
- =define-api= → Used for all JSON API endpoints (data access)
|
|
- =define-page= → Used for HTML page rendering and static file serving
|
|
|
|
** Radiance's =define-api= Pattern
|
|
|
|
Radiance's =define-api= signature:
|
|
#+BEGIN_SRC lisp
|
|
(define-api name (lambda-list) (options) body...)
|
|
#+END_SRC
|
|
|
|
Key features:
|
|
- API endpoints are accessed at =/api/<name>= automatically
|
|
- Parameters are specified in lambda-list (required and optional)
|
|
- Uses =api-output= function for responses
|
|
- Supports browser detection via =(post/get "browser")= for dual user/API usage
|
|
- Automatic JSON serialization based on configured API format
|
|
|
|
* Changes Made
|
|
|
|
** Converted Endpoints to Radiance's =define-api=
|
|
|
|
All API endpoints have been refactored from =define-page= with manual JSON handling to proper =define-api= definitions.
|
|
|
|
*** Admin API Endpoints
|
|
- =asteroid/admin/scan-library= → =/api/asteroid/admin/scan-library=
|
|
- =asteroid/admin/tracks= → =/api/asteroid/admin/tracks=
|
|
|
|
*** Playlist API Endpoints
|
|
- =asteroid/playlists= → =/api/asteroid/playlists=
|
|
- =asteroid/playlists/create= (params: name, description) → =/api/asteroid/playlists/create=
|
|
- =asteroid/playlists/add-track= (params: playlist-id, track-id) → =/api/asteroid/playlists/add-track=
|
|
- =asteroid/playlists/get= (param: playlist-id) → =/api/asteroid/playlists/get=
|
|
|
|
*** Track API Endpoints
|
|
- =asteroid/tracks= → =/api/asteroid/tracks=
|
|
|
|
*** Player Control API Endpoints
|
|
- =asteroid/player/play= (param: track-id) → =/api/asteroid/player/play=
|
|
- =asteroid/player/pause= → =/api/asteroid/player/pause=
|
|
- =asteroid/player/stop= → =/api/asteroid/player/stop=
|
|
- =asteroid/player/resume= → =/api/asteroid/player/resume=
|
|
- =asteroid/player/status= → =/api/asteroid/player/status=
|
|
|
|
*** Status API Endpoints
|
|
- =asteroid/auth-status= → =/api/asteroid/auth-status=
|
|
- =asteroid/status= → =/api/asteroid/status=
|
|
- =asteroid/icecast-status= → =/api/asteroid/icecast-status=
|
|
|
|
** Pages Still Using =define-page= (Correct Usage)
|
|
|
|
These continue to use =define-page= because they render HTML pages or serve files:
|
|
|
|
*** HTML Pages
|
|
- =front-page= - Main landing page (/)
|
|
- =admin= - Admin dashboard (/admin)
|
|
- =users-management= - User management page (/admin/user)
|
|
- =user-profile= - User profile page (/profile)
|
|
- =register= - Registration page (/register)
|
|
- =player= - Web player page (/player)
|
|
|
|
*** File Serving
|
|
- =static= - Static file serving (/static/*)
|
|
- =stream-track= - Audio file streaming (/tracks/*/stream)
|
|
|
|
*** Helper Functions
|
|
- =api-get-track-by-id= - Internal track lookup (not a public endpoint)
|
|
|
|
* Benefits
|
|
|
|
1. **Framework Compliance**: Now following Radiance's recommended patterns and best practices
|
|
2. **Automatic Routing**: Endpoints automatically available at =/api/<name>= without manual URI configuration
|
|
3. **Parameter Handling**: Clean lambda-list based parameter extraction instead of manual =post-var= calls
|
|
4. **Dual Usage**: Built-in support for both programmatic API access and browser-based usage
|
|
5. **Cleaner Code**: Uses =api-output= for consistent response formatting
|
|
6. **Better Error Handling**: Proper HTTP status codes (404, 500, etc.) for different error conditions
|
|
7. **Reduced Boilerplate**: No manual JSON encoding or header setting required
|
|
|
|
* Code Examples
|
|
|
|
** Before (using =define-page=):
|
|
#+BEGIN_SRC lisp
|
|
(define-page api-pause #@"/api/pause" ()
|
|
"Pause current playback"
|
|
(setf *player-state* :paused)
|
|
(setf (radiance:header "Content-Type") "application/json")
|
|
(cl-json:encode-json-to-string
|
|
`(("status" . "success")
|
|
("message" . "Playback paused")
|
|
("player" . ,(get-player-status)))))
|
|
#+END_SRC
|
|
|
|
** After (using Radiance's =define-api=):
|
|
#+BEGIN_SRC lisp
|
|
(define-api asteroid/player/pause () ()
|
|
"Pause current playback"
|
|
(setf *player-state* :paused)
|
|
(api-output `(("status" . "success")
|
|
("message" . "Playback paused")
|
|
("player" . ,(get-player-status)))))
|
|
#+END_SRC
|
|
|
|
** Example with Parameters:
|
|
#+BEGIN_SRC lisp
|
|
(define-api asteroid/playlists/create (name &optional description) ()
|
|
"Create a new playlist"
|
|
(require-authentication)
|
|
(handler-case
|
|
(let* ((user (get-current-user))
|
|
(user-id-raw (gethash "_id" user))
|
|
(user-id (if (listp user-id-raw) (first user-id-raw) user-id-raw)))
|
|
(create-playlist user-id name description)
|
|
(if (string= "true" (post/get "browser"))
|
|
(redirect "/asteroid/")
|
|
(api-output `(("status" . "success")
|
|
("message" . "Playlist created successfully")))))
|
|
(error (e)
|
|
(api-output `(("status" . "error")
|
|
("message" . ,(format nil "Error: ~a" e)))
|
|
:status 500))))
|
|
#+END_SRC
|
|
|
|
* Testing Recommendations
|
|
|
|
** API Endpoint URLs Changed
|
|
All API endpoints now use the new URL structure. Update any frontend code or tests:
|
|
|
|
Old format: =/api/tracks=
|
|
New format: =/api/asteroid/tracks=
|
|
|
|
** Testing Checklist
|
|
1. Test all API endpoints with new URLs to ensure proper JSON responses
|
|
2. Verify parameter passing works correctly (GET/POST parameters)
|
|
3. Test browser detection: Add =browser=true= parameter to test redirect behavior
|
|
4. Verify error handling returns proper HTTP status codes (404, 500, etc.)
|
|
5. Check that authentication/authorization still works on protected endpoints
|
|
6. Test endpoints both programmatically and via browser
|
|
|
|
** Example Test Commands
|
|
#+BEGIN_SRC bash
|
|
# Test auth status
|
|
curl http://localhost:8080/api/asteroid/auth-status
|
|
|
|
# Test with parameters
|
|
curl -X POST http://localhost:8080/api/asteroid/playlists/create \
|
|
-d "name=MyPlaylist&description=Test"
|
|
|
|
# Test browser mode (should redirect)
|
|
curl -X POST http://localhost:8080/api/asteroid/playlists/create \
|
|
-d "name=MyPlaylist&browser=true"
|
|
|
|
# Test player control
|
|
curl http://localhost:8080/api/asteroid/player/play?track-id=1
|
|
#+END_SRC
|
|
|
|
* Frontend Updates Required
|
|
|
|
The frontend JavaScript code needs to be updated to use the new API endpoint URLs:
|
|
|
|
** Files to Update
|
|
- =static/js/profile.js= - Update API calls for playlists
|
|
- =static/js/auth-ui.js= - Update auth-status endpoint
|
|
- Any other JavaScript files making API calls
|
|
|
|
** Example Changes
|
|
#+BEGIN_SRC javascript
|
|
// Old
|
|
fetch('/api/playlists')
|
|
|
|
// New
|
|
fetch('/api/asteroid/playlists')
|
|
#+END_SRC
|
|
|
|
* Migration Notes
|
|
|
|
** Breaking Changes
|
|
- All API endpoint URLs have changed from =/api/<path>= to =/api/asteroid/<name>=
|
|
- Parameters are now passed via GET/POST variables, not URI patterns
|
|
- The =asteroid/playlists/get= endpoint now requires =playlist-id= as a parameter instead of URI pattern
|
|
|
|
** Backward Compatibility
|
|
Consider adding route redirects for old API URLs during transition period:
|
|
#+BEGIN_SRC lisp
|
|
(define-route old-api-redirect "/api/tracks" ()
|
|
(redirect "/api/asteroid/tracks"))
|
|
#+END_SRC
|
|
|
|
* Next Steps
|
|
|
|
1. **Update Frontend Code**: Modify all JavaScript files to use new API URLs
|
|
2. **Test Thoroughly**: Run through all user workflows to ensure APIs work correctly
|
|
3. **Update Documentation**: Update any API documentation for external consumers
|
|
4. **Monitor Logs**: Watch for any 404 errors indicating missed endpoint updates
|
|
5. **Consider JSON Format**: May want to configure Radiance to use JSON API format instead of default S-expressions
|