Kotchasan Framework Documentation

Kotchasan Framework Documentation

ApiController Class - API Endpoint Management

TH 05 Feb 2026 07:35

ApiController Class - API Endpoint Management

คลาส ApiController เป็นคลาสพื้นฐานสำหรับการสร้าง API endpoints ในกรอบงาน Kotchasan รองรับการจัดการ routing, authentication, validation และ response แบบ RESTful API

Namespace

namespace Kotchasan;

use Kotchasan\Http\Request;
use Kotchasan\Http\Response;

ภาพรวม

ApiController จัดการทุกแง่มุมของ API development รวมถึง:

  • Routing - จัดเส้นทาง API ตาม pattern module/method/action
  • Authentication - ตรวจสอบ Token, Bearer Token, JWT
  • Authorization - ตรวจสอบ IP whitelist, CORS
  • Validation - ตรวจสอบข้อมูล input ด้วยกฎที่กำหนด
  • Response - สร้าง JSON response แบบมาตรฐาน
  • Security - CSRF protection, signature validation

ใช้เมื่อไหร่:

  • สร้าง RESTful API สำหรับ mobile apps
  • สร้าง public API สำหรับ third-party integration
  • สร้าง internal microservices
  • สร้าง AJAX endpoints สำหรับ web applications

ข้อกำหนดของระบบ

  • PHP 7.4 ขึ้นไป
  • Kotchasan Framework
  • Database connection (สำหรับ authentication)

Class Hierarchy

Kotchasan\KBase
    └── Kotchasan\ApiController (extends KBase)

การตั้งค่า (Configuration)

ต้องกำหนดค่าใน settings/config.php:

return array(
    // API Token list สำหรับ validateToken()
    'api_tokens' => [
        'your-secret-token-1',
        'your-secret-token-2'
    ],

    // IP Whitelist สำหรับ API access
    'api_ips' => [
        '0.0.0.0',      // อนุญาตทุก IP (development)
        // '192.168.1.10', // production - specific IPs only
    ],

    // CORS configuration
    'api_cors' => '*',  // หรือ 'https://your-domain.com'

    // API Secret สำหรับ signature validation
    'api_secret' => 'your-api-secret-key',

    // JWT Secret สำหรับ JWT authentication
    'jwt_secret' => 'your-jwt-secret-key'
);

Public Methods

index()

Router หลักสำหรับ API endpoints จัดการ CORS, authentication, และ routing

public function index(Request $request): void

Parameters:

  • $request (Request, required) - HTTP request object

Returns: void (ส่ง response แล้ว exit)

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()

ตรวจสอบ API token กับรายการ tokens ใน config

public static function validateToken($token): bool

Parameters:

  • $token (string, required) - Token ที่ต้องการตรวจสอบ

Returns: bool - true ถ้าถูกต้อง

Throws: ApiException - ไม่พบ token หรือไม่ถูกต้อง (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()

ตรวจสอบ Bearer token จาก Authorization header

public static function validateTokenBearer(Request $request): bool

Parameters:

  • $request (Request, required) - HTTP request object

Returns: bool - true ถ้าถูกต้อง

Throws: ApiException - ไม่พบ header หรือ token ไม่ถูกต้อง (401)

Expected Header:

Authorization: Bearer your-token-here

Example:

use Kotchasan\ApiController;
use Kotchasan\Http\Request;

class SecureApi extends ApiController
{
    public function index(Request $request)
    {
        try {
            // ตรวจสอบ 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()

ตรวจสอบ signature ของ request parameters

public static function validateSign($params): bool

Parameters:

  • $params (array, required) - Parameters รวมทั้ง 'sign' key

Returns: bool - true ถ้า signature ถูกต้อง

Throws: ApiException - signature ไม่ถูกต้อง (401)

Example:

use Kotchasan\ApiController;
use Kotchasan\Password;

// Client-side: สร้าง signature
$params = [
    'user_id' => 123,
    'action' => 'delete',
    'timestamp' => time()
];

// เรียงลำดับ keys และสร้าง signature
$params['sign'] = Password::generateSign($params, 'api-secret-key');

// Server-side: ตรวจสอบ 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()

ตรวจสอบ HTTP method ของ request

public static function validateMethod(Request $request, $method): bool

Parameters:

  • $request (Request, required) - HTTP request object
  • $method (string, required) - Expected HTTP method: 'GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'

Returns: bool - true ถ้า method ตรงกัน

Throws: ApiException - method ไม่ตรงกัน (405)

Example:

use Kotchasan\ApiController;
use Kotchasan\Http\Request;

class UserApi extends ApiController
{
    public function create(Request $request)
    {
        try {
            // ต้องเป็น POST เท่านั้น
            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 {
            // ต้องเป็น PUT เท่านั้น
            self::validateMethod($request, 'PUT');

            // Process update
            return $this->successResponse(null, 'Updated');

        } catch (\Kotchasan\ApiException $e) {
            return $this->errorResponse('Method not allowed', 405);
        }
    }
}

validateIpAddress()

ตรวจสอบ IP address ของ client กับ whitelist

public static function validateIpAddress(Request $request): bool

Parameters:

  • $request (Request, required) - HTTP request object

Returns: bool - true ถ้า IP ได้รับอนุญาต

Throws: ApiException - IP ไม่ได้รับอนุญาต (403)

Example:

use Kotchasan\ApiController;
use Kotchasan\Http\Request;

class RestrictedApi extends ApiController
{
    public function index(Request $request)
    {
        try {
            // ตรวจสอบ 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()

ตรวจสอบ authentication และคืนค่า user object

protected function authenticateRequest(Request $request): object|null

Parameters:

  • $request (Request, required) - HTTP request object

Returns: object|null - User object ถ้า authenticated, null ถ้าไม่

Authentication Methods (ตามลำดับ):

  1. Opaque token จาก database (user.token column)
  2. JWT token (ถ้ามี jwt_secret config)
  3. Cookie token (auth_token)

Example:

use Kotchasan\ApiController;
use Kotchasan\Http\Request;

class ProfileApi extends ApiController
{
    public function index(Request $request)
    {
        // ตรวจสอบ 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()

ดึง access token จาก request (header, cookie, หรือ parameter)

protected function getAccessToken(Request $request): mixed

Parameters:

  • $request (Request, required) - HTTP request object

Returns: string|null - Access token หรือ null

Token Sources (ตามลำดับ):

  1. Authorization: Bearer <token> header
  2. X-Access-Token: <token> header
  3. access_token POST parameter
  4. auth_token cookie

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()

ตรวจสอบข้อมูล request ตามกฎที่กำหนด

protected function validate(Request $request, array $rules): array

Parameters:

  • $request (Request, required) - HTTP request object
  • $rules (array, required) - Validation rules

Returns: array - [isValid (bool), errors (array)]

Validation Rules:

  • required - ค่าห้ามว่าง
  • email - รูปแบบอีเมล
  • numeric - ตัวเลข
  • integer - จำนวนเต็ม
  • min:x - ค่าต่ำสุด (number) หรือความยาวต่ำสุด (string)
  • max:x - ค่าสูงสุด (number) หรือความยาวสูงสุด (string)
  • in:a,b,c - ค่าต้องอยู่ในลิสต์
  • date - วันที่ที่ถูกต้อง
  • json - JSON string ที่ถูกต้อง
  • same:field - ต้องเหมือนกับฟิลด์อื่น
  • regex:pattern - ตรงกับ regex pattern
  • url - URL ที่ถูกต้อง
  • ip - IP address ที่ถูกต้อง
  • array - ต้องเป็น array
  • boolean - ต้องเป็น 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()

ตรวจสอบ CSRF token จาก header

protected function validateCsrfToken(Request $request): bool

Parameters:

  • $request (Request, required) - HTTP request object

Returns: bool - true ถ้า token ถูกต้อง

Throws: ApiException - 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 {
            // ตรวจสอบ 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()

กรองและ sanitize ข้อมูล input

protected function filter(array $data, array $filters): array

Parameters:

  • $data (array, required) - ข้อมูลที่ต้องการกรอง
  • $filters (array, required) - Filters ที่ต้องการใช้

Returns: array - ข้อมูลที่ผ่านการกรองแล้ว

Available Filters:

  • int - แปลงเป็น integer
  • float - แปลงเป็น float
  • bool - แปลงเป็น boolean
  • string - แปลงเป็น string
  • email - sanitize email
  • url - sanitize URL
  • strip_tags - ลบ HTML tags
  • trim - ตัด whitespace
  • Custom callable function

Example:

use Kotchasan\ApiController;
use Kotchasan\Http\Request;

class ProductApi extends ApiController
{
    public function create(Request $request)
    {
        $data = $request->getParsedBody();

        // กรองข้อมูล
        $filtered = $this->filter($data, [
            'name' => 'trim',
            'price' => 'float',
            'quantity' => 'int',
            'description' => 'strip_tags',
            'url' => 'url',
            'email' => 'email',
            'active' => 'bool'
        ]);

        // บันทึกข้อมูลที่กรองแล้ว
        return $this->successResponse($filtered);
    }
}

getRequestData()

ดึงข้อมูลจาก request ตาม HTTP method

protected function getRequestData(Request $request): array

Parameters:

  • $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)
    {
        // อัตโนมัติดึงข้อมูลตาม method
        $data = $this->getRequestData($request);

        // $data จะเป็น query params (GET) หรือ body (POST/PUT/DELETE)
        return $this->successResponse($data);
    }
}

Response Methods

successResponse()

สร้าง success response

protected function successResponse(
    $data = null,
    $message = 'Success',
    $code = 200
): Response

Parameters:

  • $data (mixed, optional) - ข้อมูลที่ต้องการส่งกลับ
  • $message (string, optional, default: 'Success') - ข้อความ
  • $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()

สร้าง error response

protected function errorResponse(
    $message = 'Error',
    $code = 400,
    $error = null
): Response

Parameters:

  • $message (string, optional, default: 'Error') - Error message
  • $code (int, optional, default: 400) - HTTP status code
  • $error (Exception, optional) - Exception object (แสดงเฉพาะ DEBUG mode)

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()

สร้าง form validation error response

protected function formErrorResponse(
    $errors,
    $code = 400,
    $error = null
): Response

Parameters:

  • $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()

สร้าง notification response (สำหรับแจ้งเตือนเท่านั้น)

protected function notificationResponse(string $message): Response

Parameters:

  • $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()

สร้าง redirect response

protected function redirectResponse(
    $url,
    $message = '',
    $code = 200,
    $delay = 0,
    $target = ''
): Response

Parameters:

  • $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:

// Redirect ทันที
return $this->redirectResponse('/dashboard', 'Login successful');

// Redirect หลัง 2 วินาที
return $this->redirectResponse('/dashboard', 'Redirecting...', 200, 2000);

// Redirect ไปหน้าต่างใหม่
return $this->redirectResponse('/external', 'Opening...', 200, 0, '_blank');

Utility Methods

initLanguage()

กำหนดภาษาจาก Accept-Language header

protected function initLanguage(Request $request): string

Parameters:

  • $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' หรือ 'en' ตาม Accept-Language header

    Language::setName($lang);

    return $this->successResponse(['language' => $lang]);
}

normalizeResult()

ปรับ result array ให้มี 'success' flag

protected function normalizeResult(?array $result): array

Parameters:

  • $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()

สร้าง standard response headers พร้อม CSRF token

protected function getResponseHeaders(): array

Parameters: ไม่มี

Returns: array - Response headers

Headers:

  • Content-Type: application/json; charset=utf-8
  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
  • Access-Control-Allow-Headers: ...
  • X-CSRF-Token: <new-token>

Example:

$headers = $this->getResponseHeaders();
// Headers includ new CSRF token for next request

ตัวอย่างการใช้งาน

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)
    {
        // ดึงรายการสินค้าทั้งหมด
        $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

✅ ควรทำ:

// 1. ใช้ try-catch สำหรับ validation
try {
    self::validateTokenBearer($request);
    self::validateMethod($request, 'POST');
} catch (\Kotchasan\ApiException $e) {
    return $this->errorResponse($e->getMessage(), $e->getCode());
}

// 2. Validate และ filter ข้อมูลก่อนใช้งาน
list($isValid, $errors) = $this->validate($request, $rules);
if (!$isValid) {
    return $this->formErrorResponse($errors);
}
$data = $this->filter($this->getRequestData($request), $filters);

// 3. ใช้ 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 ข้อผิดพลาดสำคัญ
catch (\Exception $e) {
    Logger::exception($e, 'API Error');
    return $this->errorResponse('Server error', 500);
}

❌ ไม่ควรทำ:

// 1. อย่าเปิดเผยข้อผิดพลาดโดยตรง (production)
return $this->errorResponse($e->getMessage());  // ไม่ดี - เปิดเผย internal error

// 2. อย่าใช้ GET สำหรับ operations ที่เปลี่ยนแปลงข้อมูล
public function delete(Request $request) {
    // ไม่ดี - ควรใช้ DELETE method
}

// 3. อย่าลืม validate input
$data = $request->getParsedBody();
DB::create()->insert('table', $data);  // อันตราย!

// 4. อย่า hardcode tokens
$token = '123456';  // ไม่ดี - ใช้ config

Common Mistakes

❌ ข้อผิดพลาด: ลืม validate HTTP method

// ❌ ผิด - รับทุก method
public function create(Request $request) {
    // Anyone can call with GET, POST, PUT, etc.
}

// ✅ ถูก
public function create(Request $request) {
    self::validateMethod($request, 'POST');
    // Now only POST is allowed
}

❌ ข้อผิดพลาด: ไม่ handle ApiException

// ❌ ผิด - exception จะ propagate
self::validateTokenBearer($request);

// ✅ ถูก
try {
    self::validateTokenBearer($request);
} catch (\Kotchasan\ApiException $e) {
    return $this->errorResponse($e->getMessage(), $e->getCode());
}

❌ ข้อผิดพลาด: validate() return format ผิด

// ❌ ผิด - validate() คืนค่า array 2 ตัว
$validation = $this->validate($request, $rules);
if (!$validation) {  // ผิด!
    return $this->errorResponse('Invalid');
}

// ✅ ถูก - ใช้ list() destructure
list($isValid, $errors) = $this->validate($request, $rules);
if (!$isValid) {
    return $this->formErrorResponse($errors);
}

FAQ (คำถามที่พบบ่อย)

Q: ต่างระหว่าง validateToken() และ validateTokenBearer() อย่างไร?
A:

  • validateToken($token) - ตรวจสอบ token ที่ส่งมาเป็น parameter
  • validateTokenBearer($request) - ตรวจสอบ Bearer token จาก Authorization header

Q: จะทำ API versioning ได้อย่างไร?
A: ใช้ module pattern:

/api/v1/users/index → V1\Users\Controller::index()
/api/v2/users/index → V2\Users\Controller::index()

Q: CSRF token ทำงานอย่างไร?
A:

  1. Client ได้ token จาก X-CSRF-Token response header
  2. Client ส่ง token กลับมาใน X-CSRF-TOKEN request header
  3. Server validate token กับ session

Q: JWT authentication ต้องตั้งค่าอย่างไร?
A: เพิ่ม jwt_secret ใน config.php:

'jwt_secret' => 'your-secret-key-min-32-chars'

Q: Validation rules มีอะไรบ้าง?
A: ดูรายการครบใน validate() method documentation

💡 Tip: ใช้ ApiController เป็น base class และ extend เพื่อเพิ่ม custom functionality

⚠️ Security: อย่าลืม validate input ทุกครั้งก่อนใช้งาน และ sanitiz ข้อมูลก่อนบันทึกลง database

📝 Note: Response methods ทั้งหมดคืนค่า Response object พร้อม CORS headers และ CSRF token อัตโนมัติ