Building your API

All business logic in a Pionia app lives in services — PHP classes with one method per action. Pionia Shop clients POST JSON to http://127.0.0.1:8000/api/v1/:

{ "service": "product", "action": "list" }

Who this is for

You finished Pionia Shop tutorial Step 1 and want to design Pionia Shop’s Moonlight API — services, actions, validation, and optional generic CRUD for task, member, and project.

What you will learn

  • How { "service", "action" } maps to PHP classes and *Action methods
  • When to use hand-written services vs Generic services
  • How to document actions for frontend teams at /docs
Before you start

How it works

flowchart LR
  POST["POST /api/v1/"] --> Switch[MainSwitch]
  Switch --> Task["task → ProductService"]
  Switch --> Member["member → CustomerService"]
  Switch --> Project["project → OrderService"]
  Task --> Action["listAction / createAction"]

Start here

TopicPage
Architecture overviewMoonlight overview
Your first serviceServices
Action methodsActions
Input rulesValidation
CRUD without boilerplateGeneric services

Pionia Shop services

In the Pionia Shop tutorial you build:

ServicePurpose
taskList, create, and assign tasks
memberLogin and team profiles
projectGroup tasks by client project

Reference

Every response uses the same envelope: returnCode, returnMessage, returnData. See Requests & responses.

Common mistakes

  • Legacy uppercase JSON keys — Moonlight expects lowercase service and action.
  • Skipping switch registration — scaffolding ProductService is not enough; add 'task' => ProductService::class in MainSwitch::registerServices().
  • Using generic services for complex rules — keep ProductService manual when assignee logic grows; use OrderService as generic CRUD first.
  • Wrong dev port — Pionia Shop examples use 8000 (PORT in environment/.env), not 3000 or 8003.

What’s next

Services

Register task, member, and project.

API tutorial

Continue Pionia Shop tutorial hands-on.

Validation

422 errors when title is missing.