Moonlight overview
Who this is for
You understand HTTP APIs but want to know why Pionia uses one URL and a { service, action } body instead of dozens of REST routes.
What you will learn
- How a DeskFlow request travels from curl to
TaskService::listAction - The JSON envelope every client receives
- When to add a new switch for API versioning
Before you start
- Read Introduction and run the ping curl
- Optional: Glossary for term definitions
How it works
DeskFlow clients POST to http://127.0.0.1:8000/api/v1/ with lowercase keys:
{
"service": "task",
"action": "list",
"status": "open"
}Pionia resolves task → TaskService, list → listAction(), and returns:
{
"returnCode": 0,
"returnMessage": "OK",
"returnData": { "tasks": [] }
}returnCode is the business outcome (0 = success). HTTP status still matters: validation errors use 422, auth failures 401, not-found 404.
One endpoint per API version
Each switch registers services for a version path:
| URL | Switch class |
|---|---|
/api/v1/ | Application\Switches\MainSwitch |
/api/v2/ | (future) V2Switch |
Frontend teams always know the base path; they vary service and action in the JSON body. See API versioning when Northwind ships breaking changes.
POST for actions, GET for health checks
Moonlight actions use POST with a JSON body so payloads never appear in server access logs or browser history.
Health and discovery endpoints still use normal HTTP verbs:
curl -s http://127.0.0.1:8000/api/v1/pingSecurity at the switch
Authentication runs before your action method — like checking the driver’s ID at the window, not each passenger separately. See Moonlight security model and Authentication.
Common mistakes
- Using uppercase
SERVICE/ACTION— v3 expects lowercaseservice/action - Expecting HTTP 200 for every error — check both status code and
returnCode - Using port 3000 — default dev port is 8000 (
PORTinenvironment/.env)
What’s next
Services
Create TaskService and register actions.
API tutorial
Start the DeskFlow tutorial.
Requests & responses
HTTP status codes and envelopes.