MagratheaApi — RESTful API Framework
File: src/MagratheaApi.php Namespace: Magrathea2
The central class for building RESTful APIs. Handles routing, CORS, request parsing, response formatting, JWT authorization, and caching. The recommended entry point for any API-first application.
Quick Start
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Magrathea2\MagratheaPHP;
use Magrathea2\MagratheaApi;
MagratheaPHP::LoadVendor();
MagratheaPHP::Instance()->AppPath(__DIR__)->Prod()->Load()->Connect();
$api = new MagratheaApi();
$api->AllowAll();
$api->Add("GET", "/ping", null, function() {
return ["status" => "ok"];
});
$api->Run();
Properties
| Property | Type | Description |
|---|---|---|
$control | string | Default control class |
$action | string | Default action |
$params | array | Request parameters |
$returnRaw | bool | Whether to skip JSON encoding |
$apiAddress | ?string | Base API path prefix |
$authClass | ?MagratheaApiAuth | Authorization class |
$baseAuth | ?string | Default auth method name |
$endpoints | array | All registered routes |
$fallback | callable|null | Fallback for unmatched routes |
Configuration Methods
SetAddress(string $addr): MagratheaApi
Set a base path prefix for all routes (e.g., /api/v1).
$api->SetAddress("/api/v1");
// Routes like "/users" become "/api/v1/users"
GetAddress(): string|null
Returns the current base address.
AllowAll(): MagratheaApi
Set Access-Control-Allow-Origin: * (CORS open to all origins).
$api->AllowAll();
Allow(array $allowedOrigins): MagratheaApi
Restrict CORS to specific origins.
$api->Allow(["https://myapp.com", "https://admin.myapp.com"]);
DisableCache(): MagratheaApi
Send Cache-Control: no-cache headers.
AddAcceptHeaders(string|array $accept): void
Append allowed request headers.
$api->AddAcceptHeaders(["X-Api-Key", "X-Custom-Header"]);
AcceptHeaders(?array $headers): void
Set the full list of accepted request headers.
SetRaw(): MagratheaApi
Disable JSON encoding of responses — return raw output.
BaseAuthorization(MagratheaApiControl $authClass, ?string $function): MagratheaApi
Set a default authorization check applied to all protected routes.
$api->BaseAuthorization(new AuthControl(), "ValidateToken");
Registering Endpoints
Add(string $method, string $url, ?MagratheaApiControl $control, string|callable $function, string|bool $auth = false, ?string $description = null): MagratheaApi
Register a single route.
| Parameter | Description |
|---|---|
$method | HTTP verb: "GET", "POST", "PUT", "DELETE", "PATCH" |
$url | Route pattern, supports {param} placeholders |
$control | Controller instance (null for closure-only routes) |
$function | Method name string or a callable (closure) |
$auth | false = no auth, true = use base auth, string = named auth method |
$description | Optional route description (shown in API explorer) |
// Closure route
$api->Add("GET", "/hello", null, function() {
return ["message" => "Hello!"];
});
// Controller method
$api->Add("GET", "/users", new UserApiControl(), "List");
$api->Add("GET", "/users/{id}", new UserApiControl(), "Read");
$api->Add("POST", "/users", new UserApiControl(), "Create", true); // auth required
// Route with description
$api->Add("DELETE", "/users/{id}", new UserApiControl(), "Delete", true,
"Delete a user by ID (requires admin token)");
Crud(string|array $url, MagratheaApiControl $control, string|bool $auth = false): MagratheaApi
Registers a full CRUD suite for a resource in one call:
| Method | Route | Controller Method |
|---|---|---|
| GET | /resource | List() |
| GET | /resource/{id} | Read($params) |
| POST | /resource | Create($data) |
| PUT | /resource/{id} | Update($params) |
| DELETE | /resource/{id} | Delete($params) |
$api->Crud("/products", new ProductApiControl());
// With auth on all CRUD methods:
$api->Crud("/products", new ProductApiControl(), true);
Crud() always registers Update under PUT, never PATCH — if you also want a PATCH route for the same resource/handler, register it yourself with Add():
$api->Crud("/products", new ProductApiControl());
$api->Add("PATCH", "/products/{id}", new ProductApiControl(), "Update", true);
Both PUT and PATCH bodies are read the same way in a controller — GetPut() (or its alias GetPatch()) returns the decoded body regardless of which of the two verbs was used.
Fallback(callable $fn): MagratheaApi
Register a fallback handler for routes that don't match anything.
$api->Fallback(function() {
return ["error" => "Route not found"];
});
HealthCheck(bool $checkDatabase = false): void
Registers a GET /health-check endpoint that always returns health and time.
When $checkDatabase is true, it also checks DB connectivity and adds database with "ok" or "fail".
$api->HealthCheck();
// {"health":"ok","time":"2026-07-20 10:00:00"}
$api->HealthCheck(true);
// {"health":"ok","time":"2026-07-20 10:00:00","database":"ok"}
Running the API
Run(bool $returnRaw = false): mixed
Matches the incoming request to a route, calls the controller/closure, and outputs the JSON response.
$api->Run();
ExecuteUrl(string $fullUrl, string $method = "GET"): mixed
Manually execute a URL against this API (useful for internal subrequests or tests).
$result = $api->ExecuteUrl("/products/1", "GET");
Response Helpers
These are typically called from within controllers, but can also be called directly.
Json(array|object $response, int $code = 200): mixed
Output a JSON response with an HTTP status code.
$api->Json(["error" => "Not found"], 404);
ReturnSuccess(mixed $data): mixed
Return a standardized success response:
{"success": true, "data": ...}
If $data is a MagratheaPagination instance, a paginated envelope is returned instead:
{"success": true, "data": [...], "page": 0, "count": 20, "has_more": true, "total": 143}
total is only included when it was computed (see MagratheaModelControl::GetPagination()). Just return a MagratheaPagination from a controller action — no other code changes needed:
public function List(array $params = []): MagratheaPagination {
$query = Query::Select()->Obj(new Article())->Where(["published" => 1])->Order("created_at DESC");
return ArticleControl::GetPagination($query, page: (int)($params["page"] ?? 0), limit: 20);
}
ReturnFail(mixed $data): mixed
Return a standardized failure response:
{"success": false, "data": ...}
ReturnError(int $code = 500, string $message = "", mixed $data = null, int $status = 200): mixed
Return a standardized error response.
$api->ReturnError(401, "Unauthorized");
Return404(): mixed
Return a 404 response.
ReturnApiException(MagratheaApiException $exception): mixed
Return an error response derived from an exception.
Cache(array $data): void
Store and immediately return a cached response.
Endpoint Introspection
GetEndpoints(): array
Returns all registered endpoints grouped by URL and method.
GetEndpointsDetail(): array
Returns detailed endpoint info including descriptions.
$endpoints = $api->GetEndpoints();
// Used by the Admin API Explorer feature
Debug Mode
Debug(): MagratheaApi
Enable endpoint debugging — outputs route resolution info.
$api->Debug()->Run();
URL Parameter Parsing
Route parameters defined with {param} are passed to the controller method:
$api->Add("GET", "/users/{id}/orders/{orderId}", new OrderControl(), "GetByUser");
// In OrderControl:
public function GetByUser(array $params): array {
$userId = $params["id"];
$orderId = $params["orderId"];
// ...
}
Full Example: Products API
<?php
require_once __DIR__ . '/vendor/autoload.php';
use Magrathea2\MagratheaPHP;
use Magrathea2\MagratheaApi;
use App\Api\ProductApiControl;
use App\Api\AuthControl;
MagratheaPHP::LoadVendor();
MagratheaPHP::Instance()
->AppPath(__DIR__)
->AddCodeFolder("models", "controls", "api")
->Prod()
->Load()
->Connect();
$api = new MagratheaApi();
$api->Allow(["https://myapp.com"])
->SetAddress("/api/v1")
->BaseAuthorization(new AuthControl(), "ValidateToken")
->DisableCache();
// Public endpoints
$api->Add("GET", "/products", new ProductApiControl(), "List");
$api->Add("GET", "/products/{id}", new ProductApiControl(), "Read");
// Protected endpoints
$api->Add("POST", "/products", new ProductApiControl(), "Create", true);
$api->Add("PUT", "/products/{id}", new ProductApiControl(), "Update", true);
$api->Add("DELETE", "/products/{id}", new ProductApiControl(), "Delete", true);
$api->HealthCheck();
$api->Run();
Notes
Run()outputs directly tophp://outputand exits. It should be the last call.- CORS preflight (
OPTIONSrequests) are handled automatically. - The API always returns
Content-Type: application/jsonunlessSetRaw()is used. - Use
SetAddress()consistently if your API lives under a sub-path (e.g.,/api/v2).
Class Reference — MagratheaApi
Creates and manages a RESTful API server. This class is responsible for routing requests, handling authorization, and returning JSON responses.
Sets the `Access-Control-Allow-Headers` CORS header.
| Param | Type | Default |
|---|---|---|
$headers |
?array | null |
Adds a custom endpoint to the API.
| Param | Type | Default |
|---|---|---|
$method |
string | required |
$url |
string | required |
$control |
?Magrathea2\MagratheaApiControl | required |
$function |
callable|string | required |
$auth |
string|bool | false |
$description |
?string | null |
Adds a header to the list of accepted headers for CORS.
| Param | Type | Default |
|---|---|---|
$accept |
mixed | required |
Includes CORS headers to allow requests from a specific list of origins.
| Param | Type | Default |
|---|---|---|
$allowedOrigins |
array | required |
Includes CORS headers to allow requests from any origin.
Defines the base authorization handler.
| Param | Type | Default |
|---|---|---|
$authClass |
Magrathea2\MagratheaApiControl | required |
$function |
?string | required |
Handles caching for the API response.
| Param | Type | Default |
|---|---|---|
$data |
mixed | required |
Adds a standard set of CRUD (Create, Read, Update, Delete) endpoints for a model.
| Param | Type | Default |
|---|---|---|
$url |
array|string | required |
$control |
Magrathea2\MagratheaApiControl | required |
$auth |
string|bool | false |
Prints a debug view of all registered endpoints.
Sets headers to disable browser and proxy caching.
Finds the matching endpoint for a given URL and method, and executes it.
| Param | Type | Default |
|---|---|---|
$fullUrl |
mixed | required |
$method |
mixed | "GET" |
Sets a fallback function to be called when no route matches the request.
| Param | Type | Default |
|---|---|---|
$fn |
mixed | required |
Gets the base address of the API.
Gets a structured array of all registered endpoints, grouped by control class.
Gets a detailed list of all endpoints, grouped by URL.
Creates a simple `/health-check` endpoint.
| Param | Type | Default |
|---|---|---|
$checkDatabase |
bool | false |
Outputs a JSON response and terminates the script.
| Param | Type | Default |
|---|---|---|
$response |
mixed | required |
$code |
int | 200 |
Formats and returns a MagratheaApiException as a JSON response.
| Param | Type | Default |
|---|---|---|
$exception |
mixed | required |
Returns a generic JSON error response.
| Param | Type | Default |
|---|---|---|
$code |
mixed | 500 |
$message |
mixed | "" |
$data |
mixed | null |
$status |
mixed | 200 |
Returns a failure JSON response.
| Param | Type | Default |
|---|---|---|
$data |
mixed | required |
Returns a successful JSON response. If $data is a MagratheaPagination, builds a paginated envelope instead ({success, data, page, count, has_more, total?}).
| Param | Type | Default |
|---|---|---|
$data |
mixed | required |
Starts the API, processes the request, and returns the response.
| Param | Type | Default |
|---|---|---|
$returnRaw |
mixed | false |
Sets the base address for the API.
| Param | Type | Default |
|---|---|---|
$addr |
mixed | required |
Configures the API to return the raw result instead of a JSON-encoded response.
Start the server, getting base calls
Constructor. Initializes the endpoint arrays for different HTTP methods.