Documentation
Quick Navigation
Building JSON APIs
Learn how to create RESTful JSON APIs with TikNix. For framework basics, see the Getting Started guide.
API Controller Pattern
API Controller Example
<?php
namespace app;
class Api extends BaseControls\Control {
public function __construct() {
parent::__construct();
// Set JSON headers
header('Content-Type: application/json');
// Check API authentication
if (!$this->checkApiAuth()) {
$this->json(['error' => 'Unauthorized'], 401);
exit;
}
}
// GET /api/users
public function users($params = []) {
$operation = $params['operation']->name ?? 'list';
switch ($operation) {
case 'list':
$this->listUsers();
break;
case 'search':
$this->searchUsers();
break;
default:
$this->json(['error' => 'Invalid operation'], 400);
}
}
private function listUsers() {
// Pagination
$page = $this->getParam('page', 1);
$limit = $this->getParam('limit', 20);
$offset = ($page - 1) * $limit;
// Get users (automatically cached!)
$users = R::find('member',
'status = ? ORDER BY created_at DESC LIMIT ? OFFSET ?',
['active', $limit, $offset]
);
$total = R::count('member', 'status = ?', ['active']);
$this->json([
'success' => true,
'data' => array_values(R::exportAll($users)),
'meta' => [
'total' => $total,
'page' => $page,
'limit' => $limit,
'pages' => ceil($total / $limit)
]
]);
}
private function checkApiAuth() {
$apiKey = $_SERVER['HTTP_X_API_KEY'] ?? '';
if (empty($apiKey)) {
return false;
}
// Check API key (cached!)
$member = R::findOne('member', 'api_key = ? AND status = ?',
[$apiKey, 'active']
);
if ($member) {
$this->member = $member;
return true;
}
return false;
}
}
Testing API Endpoints
# GET request with API key
curl -H "X-API-Key: your-key-here" https://site.com/api/users
# POST with JSON data
curl -X POST https://site.com/api/users/create \
-H "Content-Type: application/json" \
-H "X-API-Key: your-key-here" \
-d '{"username":"john","email":"john@example.com"}'
# With pagination
curl "https://site.com/api/users?page=2&limit=10" \
-H "X-API-Key: your-key-here"
Response Helpers
JSON Responses
// Success response
$this->json([
'success' => true,
'message' => 'User created',
'data' => ['id' => $id]
], 201);
// Error response
$this->json([
'success' => false,
'error' => 'Validation failed',
'errors' => [
'email' => 'Email already exists'
]
], 422);
// Using Flight directly
Flight::json(['data' => $data], 200);
Redirects
// Simple redirect
Flight::redirect('/dashboard');
// With query parameters
Flight::redirect('/auth/login?redirect=' . urlencode(Flight::request()->url));
// External redirect
Flight::redirect('https://example.com', 302);
Request Handling
Accessing Request Data
// Get Flight request object
$request = Flight::request();
// URL and path info
$url = $request->url; // Full URL path
$method = $request->method; // GET, POST, etc.
$ajax = $request->ajax; // Is AJAX request?
$secure = $request->secure; // Is HTTPS?
$ip = $request->ip; // Client IP
// Query parameters (GET)
$page = $request->query->page ?? 1;
$search = $request->query['search'] ?? '';
// Body parameters (POST)
$username = $request->data->username;
$email = $request->data['email'];
// Headers
$apiKey = $request->header('X-API-Key');
$contentType = $request->header('Content-Type');
// Files
$uploadedFile = $request->files['upload'] ?? null;
Session Management
// Set session data
$_SESSION['user_preference'] = 'dark_mode';
// Get session data
$pref = $_SESSION['user_preference'] ?? 'light_mode';
// Login a user
$_SESSION['member'] = $member->export();
// Logout
unset($_SESSION['member']);
session_destroy();
Error Handling
// In controller constructor
set_exception_handler(function($e) {
$this->logger->error($e->getMessage(), [
'file' => $e->getFile(),
'line' => $e->getLine()
]);
if ($this->getParam('format') === 'json') {
$this->json(['error' => 'Internal server error'], 500);
} else {
Flight::renderView('error/500');
}
});
// Manual error handling
try {
$result = $this->riskyOperation();
} catch (\Exception $e) {
$this->logger->error('Operation failed: ' . $e->getMessage());
$this->flash('error', 'Something went wrong');
Flight::redirect('/dashboard');
}
Performance Note
All database queries are automatically cached by the CachedDatabaseAdapter, providing 9.4x faster performance with zero code changes!