Kotchasan Framework Documentation
ApiController Class - API Endpoint Management
ApiController Class - API Endpoint Management
The ApiController class is a base class for creating API endpoints in the Kotchasan Framework. It supports routing, authentication, validation, and RESTful API response management.
Namespace
namespace Kotchasan;
use Kotchasan\Http\Request;
use Kotchasan\Http\Response;Overview
ApiController handles all aspects of API development including:
- Routing - Routes API by pattern
module/method/action - Authentication - Validates Token, Bearer Token, JWT
- Authorization - Checks IP whitelist, CORS
- Validation - Validates input data with defined rules
- Response - Creates standardized JSON responses
- Security - CSRF protection, signature validation
When to use:
- Building RESTful APIs for mobile apps
- Creating public APIs for third-party integration
- Building internal microservices
- Creating AJAX endpoints for web applications
System Requirements
- PHP 7.4 or higher
- Kotchasan Framework
- Database connection (for authentication)
Class Hierarchy
Kotchasan\KBase
└── Kotchasan\ApiController (extends KBase)Configuration
Configure in settings/config.php:
return array(
// API Token list for validateToken()
'api_tokens' => [
'your-secret-token-1',
'your-secret-token-2'
],
// IP Whitelist for API access
'api_ips' => [
'0.0.0.0', // Allow all IPs (development)
// '192.168.1.10', // production - specific IPs only
],
// CORS configuration
'api_cors' => '*', // or 'https://your-domain.com'
// API Secret for signature validation
'api_secret' => 'your-api-secret-key',
// JWT Secret for JWT authentication
'jwt_secret' => 'your-jwt-secret-key'
);Public Methods
index()
Main router for API endpoints, handles CORS, authentication, and routing
public function index(Request $request): voidParameters:
$request(Request, required) - HTTP request object
Returns: void (sends response and exits)
Routing Pattern:
/api/module/method/action
↓ ↓ ↓
Module Method Action
Example:
/api/v1/auth/login → V1\Auth\Controller::login($request)
/api/v1/user/profile → V1\User\Controller::profile($request)Example:
namespace Kotchasan;
use Kotchasan\Http\Request;
class ApiController extends \Kotchasan\KBase
{
public function index(Request $request)
{
// Framework handles routing automatically
// This method is called by index.php for /api/* routes
}
}Static Validation Methods
validateToken()
Validates API token against config token list
public static function validateToken($token): boolParameters:
$token(string, required) - Token to validate
Returns: bool - true if valid
Throws: ApiException - token not found or invalid (401)
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class MyApiController extends ApiController
{
public function index(Request $request)
{
try {
$token = $request->post('token')->toString();
self::validateToken($token);
// Token valid - proceed
return $this->successResponse(['message' => 'Authenticated']);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), $e->getCode());
}
}
}validateTokenBearer()
Validates Bearer token from Authorization header
public static function validateTokenBearer(Request $request): boolParameters:
$request(Request, required) - HTTP request object
Returns: bool - true if valid
Throws: ApiException - header not found or token invalid (401)
Expected Header:
Authorization: Bearer your-token-hereExample:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class SecureApi extends ApiController
{
public function index(Request $request)
{
try {
// Validate Bearer token
self::validateTokenBearer($request);
// Authenticated - proceed with API logic
return $this->successResponse([
'user' => 'authenticated',
'data' => []
]);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), 401);
}
}
}validateSign()
Validates signature of request parameters
public static function validateSign($params): boolParameters:
$params(array, required) - Parameters including 'sign' key
Returns: bool - true if signature is valid
Throws: ApiException - invalid signature (401)
Example:
use Kotchasan\ApiController;
use Kotchasan\Password;
// Client-side: Generate signature
$params = [
'user_id' => 123,
'action' => 'delete',
'timestamp' => time()
];
// Sort keys and generate signature
$params['sign'] = Password::generateSign($params, 'api-secret-key');
// Server-side: Validate signature
class SignedApi extends ApiController
{
public function index(Request $request)
{
$params = $request->getQueryParams();
try {
self::validateSign($params);
// Signature valid - safe to proceed
return $this->successResponse(['verified' => true]);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse('Invalid signature', 401);
}
}
}validateMethod()
Validates HTTP method of request
public static function validateMethod(Request $request, $method): boolParameters:
$request(Request, required) - HTTP request object$method(string, required) - Expected HTTP method: 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'
Returns: bool - true if method matches
Throws: ApiException - method mismatch (405)
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class UserApi extends ApiController
{
public function create(Request $request)
{
try {
// Must be POST only
self::validateMethod($request, 'POST');
// Process creation
return $this->successResponse(null, 'Created', 201);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse('Method not allowed', 405);
}
}
public function update(Request $request)
{
try {
// Must be PUT only
self::validateMethod($request, 'PUT');
// Process update
return $this->successResponse(null, 'Updated');
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse('Method not allowed', 405);
}
}
}validateIpAddress()
Validates client IP address against whitelist
public static function validateIpAddress(Request $request): boolParameters:
$request(Request, required) - HTTP request object
Returns: bool - true if IP is allowed
Throws: ApiException - IP not allowed (403)
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class RestrictedApi extends ApiController
{
public function index(Request $request)
{
try {
// Check IP whitelist
self::validateIpAddress($request);
// IP allowed - proceed
return $this->successResponse(['access' => 'granted']);
} catch (\Kotchasan\ApiException $e) {
// Log security event
Logger::security('BLOCKED_IP', [
'ip' => $request->getClientIp(),
'endpoint' => $request->getUri()
]);
return $this->errorResponse('Access denied', 403);
}
}
}Protected Helper Methods
Authentication Methods
authenticateRequest()
Validates authentication and returns user object
protected function authenticateRequest(Request $request): object|nullParameters:
$request(Request, required) - HTTP request object
Returns: object|null - User object if authenticated, null otherwise
Authentication Methods (in order):
- Opaque token from database (
user.tokencolumn) - JWT token (if
jwt_secretconfig exists) - Cookie token (
auth_token)
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class ProfileApi extends ApiController
{
public function index(Request $request)
{
// Check user authentication
$user = $this->authenticateRequest($request);
if (!$user) {
return $this->errorResponse('Unauthorized', 401);
}
// Return user profile
return $this->successResponse([
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
]);
}
}getAccessToken()
Extracts access token from request (header, cookie, or parameter)
protected function getAccessToken(Request $request): mixedParameters:
$request(Request, required) - HTTP request object
Returns: string|null - Access token or null
Token Sources (in order):
Authorization: Bearer <token>headerX-Access-Token: <token>headeraccess_tokenPOST parameterauth_tokencookie
Example:
use Kotchasan\ApiController;
class TokenApi extends ApiController
{
public function verify(Request $request)
{
$token = $this->getAccessToken($request);
if (!$token) {
return $this->errorResponse('No token provided', 401);
}
// Verify token...
return $this->successResponse([
'token' => substr($token, 0, 10) . '...',
'valid' => true
]);
}
}Validation Methods
validate()
Validates request data against defined rules
protected function validate(Request $request, array $rules): arrayParameters:
$request(Request, required) - HTTP request object$rules(array, required) - Validation rules
Returns: array - [isValid (bool), errors (array)]
Validation Rules:
required- Cannot be emptyemail- Email formatnumeric- Numeric valueinteger- Integer valuemin:x- Minimum value (number) or length (string)max:x- Maximum value (number) or length (string)in:a,b,c- Value must be in listdate- Valid datejson- Valid JSON stringsame:field- Must match another fieldregex:pattern- Must match regex patternurl- Valid URLip- Valid IP addressarray- Must be arrayboolean- Must be boolean
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class RegisterApi extends ApiController
{
public function index(Request $request)
{
$rules = [
'email' => 'required|email',
'password' => 'required|min:8',
'age' => 'integer|min:18|max:100',
'role' => 'in:user,admin,moderator',
'website' => 'url',
'terms' => 'required|boolean'
];
list($isValid, $errors) = $this->validate($request, $rules);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
// Validation passed - create user
return $this->successResponse(null, 'Registration successful', 201);
}
}validateCsrfToken()
Validates CSRF token from header
protected function validateCsrfToken(Request $request): boolParameters:
$request(Request, required) - HTTP request object
Returns: bool - true if token is valid
Throws: ApiException - invalid or missing token (403)
Expected Header:
X-CSRF-TOKEN: <64-char-hex-token>Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class FormApi extends ApiController
{
public function submit(Request $request)
{
try {
// Validate CSRF token
$this->validateCsrfToken($request);
// Process form submission
return $this->successResponse(null, 'Form submitted');
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse('CSRF validation failed', 403);
}
}
}Filtering Methods
filter()
Filters and sanitizes input data
protected function filter(array $data, array $filters): arrayParameters:
$data(array, required) - Data to filter$filters(array, required) - Filters to apply
Returns: array - Filtered data
Available Filters:
int- Convert to integerfloat- Convert to floatbool- Convert to booleanstring- Convert to stringemail- Sanitize emailurl- Sanitize URLstrip_tags- Remove HTML tagstrim- Remove whitespace- Custom callable function
Example:
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class ProductApi extends ApiController
{
public function create(Request $request)
{
$data = $request->getParsedBody();
// Filter data
$filtered = $this->filter($data, [
'name' => 'trim',
'price' => 'float',
'quantity' => 'int',
'description' => 'strip_tags',
'url' => 'url',
'email' => 'email',
'active' => 'bool'
]);
// Save filtered data
return $this->successResponse($filtered);
}
}getRequestData()
Extracts data from request based on HTTP method
protected function getRequestData(Request $request): arrayParameters:
$request(Request, required) - HTTP request object
Returns: array - Request data
Behavior:
- GET → Query parameters
- POST/PUT/PATCH/DELETE → Parsed body
Example:
use Kotchasan\ApiController;
class DataApi extends ApiController
{
public function process(Request $request)
{
// Automatically extract data based on method
$data = $this->getRequestData($request);
// $data will be query params (GET) or body (POST/PUT/DELETE)
return $this->successResponse($data);
}
}Response Methods
successResponse()
Creates success response
protected function successResponse(
$data = null,
$message = 'Success',
$code = 200
): ResponseParameters:
$data(mixed, optional) - Data to return$message(string, optional, default: 'Success') - Message$code(int, optional, default: 200) - HTTP status code
Returns: Response - JSON response object
Response Format:
{
"success": true,
"message": "Success",
"code": 200,
"data": { ... }
}Example:
return $this->successResponse(['id' => 123], 'Created', 201);
// Output:
// {
// "success": true,
// "message": "Created",
// "code": 201,
// "data": {"id": 123}
// }errorResponse()
Creates error response
protected function errorResponse(
$message = 'Error',
$code = 400,
$error = null
): ResponseParameters:
$message(string, optional, default: 'Error') - Error message$code(int, optional, default: 400) - HTTP status code$error(Exception, optional) - Exception object (shown in DEBUG mode only)
Returns: Response - JSON error response
Response Format:
{
"success": false,
"message": "Error message",
"code": 400
}Example:
return $this->errorResponse('Invalid email', 400);
return $this->errorResponse('Unauthorized', 401);
return $this->errorResponse('Not found', 404);
return $this->errorResponse('Server error', 500);formErrorResponse()
Creates form validation error response
protected function formErrorResponse(
$errors,
$code = 400,
$error = null
): ResponseParameters:
$errors(array, required) - Validation errors$code(int, optional, default: 400) - HTTP status code$error(Exception, optional) - Exception object
Returns: Response - JSON response with errors
Response Format:
{
"success": false,
"code": 400,
"errors": {
"email": ["Invalid email format"],
"password": ["Password must be at least 8 characters"]
}
}Example:
$errors = [
'email' => ['The email field is required.'],
'password' => ['The password must be at least 8 characters.']
];
return $this->formErrorResponse($errors);notificationResponse()
Creates notification response (notification only)
protected function notificationResponse(string $message): ResponseParameters:
$message(string, required) - Notification message
Returns: Response - JSON response with notification action
Response Format:
{
"success": true,
"message": "Operation completed",
"code": 200,
"data": {
"actions": [
{
"type": "notification",
"message": "Operation completed"
}
]
}
}Example:
return $this->notificationResponse('Email sent successfully');redirectResponse()
Creates redirect response
protected function redirectResponse(
$url,
$message = '',
$code = 200,
$delay = 0,
$target = ''
): ResponseParameters:
$url(string, required) - Redirect URL$message(string, optional) - Message to display$code(int, optional, default: 200) - HTTP status code$delay(int, optional, default: 0) - Delay in milliseconds$target(string, optional) - Target window
Returns: Response - JSON response with redirect action
Response Format:
{
"success": true,
"message": "Success",
"code": 200,
"data": {
"actions": [
{
"type": "redirect",
"url": "/dashboard",
"delay": 1000
},
{
"type": "notification",
"message": "Login successful",
"level": "success"
}
]
}
}Example:
// Immediate redirect
return $this->redirectResponse('/dashboard', 'Login successful');
// Redirect after 2 seconds
return $this->redirectResponse('/dashboard', 'Redirecting...', 200, 2000);
// Redirect to new window
return $this->redirectResponse('/external', 'Opening...', 200, 0, '_blank');Utility Methods
initLanguage()
Initializes language from Accept-Language header
protected function initLanguage(Request $request): stringParameters:
$request(Request, required) - HTTP request object
Returns: string - Language code ('th', 'en', etc.)
Example:
public function index(Request $request)
{
$lang = $this->initLanguage($request);
// $lang = 'th' or 'en' based on Accept-Language header
Language::setName($lang);
return $this->successResponse(['language' => $lang]);
}normalizeResult()
Normalizes result array to include 'success' flag
protected function normalizeResult(?array $result): arrayParameters:
$result(array|null, required) - Result array
Returns: array - Normalized result with 'success' field
Example:
$result = ['code' => 200, 'data' => []];
$normalized = $this->normalizeResult($result);
// $normalized = ['code' => 200, 'data' => [], 'success' => true]getResponseHeaders()
Creates standard response headers with CSRF token
protected function getResponseHeaders(): arrayParameters: None
Returns: array - Response headers
Headers:
Content-Type: application/json; charset=utf-8Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONSAccess-Control-Allow-Headers: ...X-CSRF-Token: <new-token>
Example:
$headers = $this->getResponseHeaders();
// Headers include new CSRF token for next requestUsage Examples
Example 1: Basic API Controller
namespace V1\Products;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class Controller extends ApiController
{
/**
* GET /api/v1/products/index
*/
public function index(Request $request)
{
// Get all active products
$products = \Kotchasan\DB::create()
->select()
->from('products')
->where(['active', 1])
->fetchAll();
return $this->successResponse($products);
}
/**
* POST /api/v1/products/create
*/
public function create(Request $request)
{
try {
// Validate HTTP method
self::validateMethod($request, 'POST');
// Validate input
list($isValid, $errors) = $this->validate($request, [
'name' => 'required|min:3',
'price' => 'required|numeric|min:0',
'quantity' => 'integer|min:0'
]);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
// Filter data
$data = $this->filter($this->getRequestData($request), [
'name' => 'trim',
'price' => 'float',
'quantity' => 'int',
'description' => 'strip_tags'
]);
// Insert into database
$db = \Kotchasan\DB::create();
$db->insert('products', $data)->execute();
$id = $db->lastInsertId();
return $this->successResponse(['id' => $id], 'Product created', 201);
} catch (\Exception $e) {
return $this->errorResponse('Failed to create product', 500, $e);
}
}
}Example 2: Authentication with JWT
namespace V1\Auth;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
use Kotchasan\Jwt;
use Kotchasan\Password;
class Controller extends ApiController
{
/**
* POST /api/v1/auth/login
*/
public function login(Request $request)
{
// Validate input
list($isValid, $errors) = $this->validate($request, [
'email' => 'required|email',
'password' => 'required'
]);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
$email = $request->post('email')->toString();
$password = $request->post('password')->toString();
// Find user
$user = \Kotchasan\DB::create()
->first('user', [['email', $email]]);
if (!$user || !Password::verify($password, $user->password)) {
return $this->errorResponse('Invalid credentials', 401);
}
// Generate JWT token
$payload = [
'sub' => $user->id,
'email' => $user->email,
'exp' => time() + 3600 // 1 hour
];
$token = Jwt::encode($payload, self::$cfg->jwt_secret);
return $this->successResponse([
'token' => $token,
'expires_in' => 3600,
'user' => [
'id' => $user->id,
'email' => $user->email,
'name' => $user->name
]
]);
}
/**
* GET /api/v1/auth/profile
*/
public function profile(Request $request)
{
// Authenticate user
$user = $this->authenticateRequest($request);
if (!$user) {
return $this->errorResponse('Unauthorized', 401);
}
return $this->successResponse([
'id' => $user->id,
'email' => $user->email,
'name' => $user->name
]);
}
}Example 3: CSRF Protected API
namespace V1\Form;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class Controller extends ApiController
{
/**
* POST /api/v1/form/submit
*/
public function submit(Request $request)
{
try {
// Validate CSRF token
$this->validateCsrfToken($request);
// Validate input
list($isValid, $errors) = $this->validate($request, [
'name' => 'required',
'email' => 'required|email',
'message' => 'required|min:10'
]);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
// Process form...
return $this->successResponse(null, 'Form submitted successfully');
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), $e->getCode());
}
}
}Example 4: Complete CRUD API
namespace V1\Users;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
use Kotchasan\DB;
class Controller extends ApiController
{
/**
* GET /api/v1/users/index - List all users
*/
public function index(Request $request)
{
$users = DB::create()
->select('id', 'name', 'email', 'created_at')
->from('user')
->fetchAll();
return $this->successResponse($users);
}
/**
* GET /api/v1/users/view - View single user
*/
public function view(Request $request)
{
$id = $request->get('id')->toInt();
if ($id <= 0) {
return $this->errorResponse('Invalid ID', 400);
}
$user = DB::create()->first('user', [['id', $id]]);
if (!$user) {
return $this->errorResponse('User not found', 404);
}
return $this->successResponse([
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at
]);
}
/**
* POST /api/v1/users/create - Create user
*/
public function create(Request $request)
{
self::validateMethod($request, 'POST');
list($isValid, $errors) = $this->validate($request, [
'name' => 'required|min:3',
'email' => 'required|email',
'password' => 'required|min:8'
]);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
$data = $this->filter($this->getRequestData($request), [
'name' => 'trim',
'email' => 'email'
]);
$data['password'] = \Kotchasan\Password::hash($request->post('password')->toString());
$data['created_at'] = date('Y-m-d H:i:s');
$db = DB::create();
$db->insert('user', $data)->execute();
$id = $db->lastInsertId();
return $this->successResponse(['id' => $id], 'User created', 201);
}
/**
* PUT /api/v1/users/update - Update user
*/
public function update(Request $request)
{
self::validateMethod($request, 'PUT');
$id = $request->get('id')->toInt();
if ($id <= 0) {
return $this->errorResponse('Invalid ID', 400);
}
list($isValid, $errors) = $this->validate($request, [
'name' => 'min:3',
'email' => 'email'
]);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
$data = $this->filter($this->getRequestData($request), [
'name' => 'trim',
'email' => 'email'
]);
DB::create()
->update('user')
->set($data)
->where([['id', $id]])
->execute();
return $this->successResponse(null, 'User updated');
}
/**
* DELETE /api/v1/users/delete - Delete user
*/
public function delete(Request $request)
{
self::validateMethod($request, 'DELETE');
$id = $request->get('id')->toInt();
if ($id <= 0) {
return $this->errorResponse('Invalid ID', 400);
}
DB::create()
->delete('user', [['id', $id]])
->execute();
return $this->successResponse(null, 'User deleted');
}
}Example 5: IP Whitelist & Bearer Token
namespace V1\Secure;
use Kotchasan\ApiController;
use Kotchasan\Http\Request;
class Controller extends ApiController
{
/**
* GET /api/v1/secure/data
*
* Requires:
* - IP whitelist
* - Bearer token
*/
public function data(Request $request)
{
try {
// Check IP whitelist
self::validateIpAddress($request);
// Check Bearer token
self::validateTokenBearer($request);
// Both validations passed - return sensitive data
return $this->successResponse([
'sensitive' => 'data',
'access_granted' => true
]);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), $e->getCode());
}
}
}Best Practices
✅ DO:
// 1. Use try-catch for validation
try {
self::validateTokenBearer($request);
self::validateMethod($request, 'POST');
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), $e->getCode());
}
// 2. Validate and filter data before use
list($isValid, $errors) = $this->validate($request, $rules);
if (!$isValid) {
return $this->formErrorResponse($errors);
}
$data = $this->filter($this->getRequestData($request), $filters);
// 3. Use correct HTTP status codes
return $this->successResponse($data, 'Created', 201); // Created
return $this->errorResponse('Not found', 404); // Not found
return $this->errorResponse('Unauthorized', 401); // Unauthorized
// 4. Log important errors
catch (\Exception $e) {
Logger::exception($e, 'API Error');
return $this->errorResponse('Server error', 500);
}❌ DON'T:
// 1. Don't expose errors directly (production)
return $this->errorResponse($e->getMessage()); // Bad - exposes internal error
// 2. Don't use GET for data-changing operations
public function delete(Request $request) {
// Bad - should use DELETE method
}
// 3. Don't forget to validate input
$data = $request->getParsedBody();
DB::create()->insert('table', $data); // Dangerous!
// 4. Don't hardcode tokens
$token = '123456'; // Bad - use configCommon Mistakes
❌ Mistake: Forgetting to validate HTTP method
// ❌ Wrong - accepts all methods
public function create(Request $request) {
// Anyone can call with GET, POST, PUT, etc.
}
// ✅ Correct
public function create(Request $request) {
self::validateMethod($request, 'POST');
// Now only POST is allowed
}❌ Mistake: Not handling ApiException
// ❌ Wrong - exception will propagate
self::validateTokenBearer($request);
// ✅ Correct
try {
self::validateTokenBearer($request);
} catch (\Kotchasan\ApiException $e) {
return $this->errorResponse($e->getMessage(), $e->getCode());
}❌ Mistake: Wrong validate() return format
// ❌ Wrong - validate() returns array of 2 items
$validation = $this->validate($request, $rules);
if (!$validation) { // Wrong!
return $this->errorResponse('Invalid');
}
// ✅ Correct - use list() to destructure
list($isValid, $errors) = $this->validate($request, $rules);
if (!$isValid) {
return $this->formErrorResponse($errors);
}FAQ (Frequently Asked Questions)
Q: What's the difference between validateToken() and validateTokenBearer()?
A:
validateToken($token)- Validates token sent as parametervalidateTokenBearer($request)- Validates Bearer token from Authorization header
Q: How do I implement API versioning?
A: Use module pattern:
/api/v1/users/index → V1\Users\Controller::index()
/api/v2/users/index → V2\Users\Controller::index()Q: How does CSRF token work?
A:
- Client receives token from
X-CSRF-Tokenresponse header - Client sends token back in
X-CSRF-TOKENrequest header - Server validates token against session
Q: How do I configure JWT authentication?
A: Add jwt_secret to config.php:
'jwt_secret' => 'your-secret-key-min-32-chars'Q: What validation rules are available?
A: See complete list in validate() method documentation
Related Classes
- Request - HTTP Request handling
- Response - HTTP Response handling
- Database - Database operations
- Jwt - JWT token handling
- Password - Password hashing and verification
💡 Tip: Use ApiController as base class and extend to add custom functionality
⚠️ Security: Always validate input before use and sanitize data before saving to database
📝 Note: All response methods return Response object with CORS headers and CSRF token automatically