Trongate Way Docs

Before and After Hooks

You will have noticed by now that every endpoint in our API follows the same structure:

PHP
public function some_endpoint(): void {
    $this->authenticate();     // ← before hook
    // ... endpoint logic ...
    $this->log_request(...);   // ← after hook
}

The authenticate() call runs before the endpoint logic. The log_request() call runs after. These are our before and after hooks - explicit, opt-in, and transparent.

Why Explicit Hooks?

Some frameworks use magic: they automatically detect methods named _before() or _after() and invoke them around every controller action. Trongate does not do this, for three reasons:

  • Explicitness: Looking at a controller method, you can see exactly what runs, in what order. There is no hidden code executing around your logic.
  • Selective application: Some endpoints may not need authentication (a public health-check endpoint, for example). With explicit calls, you choose per-endpoint.
  • Debuggability: If something goes wrong, the stack trace shows exactly which method called which. No magic wrappers to unravel.

The Before Hook: Authentication

Our authenticate() method checks for a valid Trongate token and terminates the request with a 401 response if none is found:

PHP
public function authenticate(): void {
    block_url('countries_api/authenticate');

    $token = $this->trongate_tokens->attempt_get_valid_token();

    if ($token === false) {
        http_response_code(401);
        echo json_encode([
            'error' => 'Unauthorized. '
                     . 'A valid API token is required.'
        ]);
        die();
    }
}

This uses Trongate_tokens::attempt_get_valid_token() with no user-level filter, meaning any valid token (from any logged-in user) is accepted. To require admin-level access, pass a user level ID:

PHP
// Require admin level (typically ID 1)
$token = $this->trongate_tokens->attempt_get_valid_token(1);

If no valid token is found, the method calls die() after sending the 401 response. This stops execution immediately - the endpoint logic never runs.

Remember: requiring authentication on every endpoint is a choice, not a framework mandate. You decide which endpoints need tokens, which user levels are allowed, and whether some should remain public. Trongate provides the Trongate_tokens module and the attempt_get_valid_token() method; you define the security policy.

For a full understanding of how tokens work, see Understanding Trongate's Token System in the framework documentation.

The After Hook: Request Logging

The log_request() method appends an entry to a log file after every successful API call:

PHP
public function log_request(
    string $action, ?int $record_id = null
): void {
    block_url('countries_api/log_request');

    $log_entry = date('Y-m-d H:i:s') . ' | '
               . $_SERVER['REQUEST_METHOD'] . ' | '
               . $action
               . ($record_id !== null
                   ? ' | id: ' . $record_id
                   : '')
               . ' | '
               . ($_SERVER['REMOTE_ADDR'] ?? 'unknown')
               . PHP_EOL;

    $log_file = APPPATH
              . 'modules/countries_api/logs/'
              . 'api_requests.log';

    file_put_contents(
        $log_file, $log_entry, FILE_APPEND | LOCK_EX
    );
}

Each log entry records the timestamp, HTTP method, action name, affected record ID (if any), and the client's IP address. Over time, this builds a complete audit trail of API activity.

Extending the Pattern

Once you have adopted the before/after hook pattern, adding new cross-cutting concerns becomes straightforward. Here are two examples:

Rate Limiting (Before Hook)

PHP
public function rate_limit(): void {
    block_url('countries_api/rate_limit');

    $ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    $window = 60; // seconds
    $max_requests = 30;

    // Implementation: track request timestamps per IP
    // in a file or database, then check the count
    // within the time window.
    // If exceeded: http_response_code(429); die();
}

Call it after authenticate() in each endpoint:

PHP
public function get_all(): void {
    $this->authenticate();
    $this->rate_limit();
    // ... rest of endpoint logic
}

Response Wrapping (After Hook)

PHP
public function wrap_response(
    mixed $data, int $status_code
): void {
    block_url('countries_api/wrap_response');

    http_response_code($status_code);
    echo json_encode([
        'status' => $status_code,
        'timestamp' => time(),
        'data' => $data
    ]);
}

This would replace the individual http_response_code() + echo json_encode() calls in every endpoint, giving you a single place to modify the response format across the entire API.

The Contract

The before/after hook pattern in Trongate is a convention, not a framework feature. The contract is simple:

  • Before hooks run at the start of each endpoint. If they detect a problem, they send an error response and terminate.
  • After hooks run at the end of each endpoint, after the response body has been prepared but before the method returns.

Because this is explicit code rather than automatic magic, you remain in full control. You decide which hooks run on which endpoints, in what order, and with what logic.

We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.

Share your thoughts in the Documentation Feedback.

Leave Feedback About This Page