W tym wpisie opiszę, jak zbudować lekkie, rozszerzalne REST API w WordPressie w czystym PHP, bazujące na abstrakcyjnej klasie, z mechanizmem API key, rate limitingiem oraz prostą obsługą danych.
Całość implementacji opiera się na dobrze udokumentowanych metodach PHP z wykorzystaniem PHPDoc, dzięki czemu kod jest samodokumentujący i łatwy do dalszej rozbudowy.
<?php
namespace API;
use WP_REST_Server;
use WP_REST_Request;
use WP_Error;
/**
* Abstrakcyjna klasa bazowa dla REST API w WordPress
*
* Zapewnia:
* - sprawdzanie klucza API
* - rate limiting (sliding window)
* - helper do zwracania danych
* - helper do rejestracji endpointów
*/
abstract class AbstractApi {
/**
* Klucz API wymagany do autoryzacji
* @var string
*/
protected const API_KEY = 'MOJ_SEKRETNY_KLUCZ';
/**
* Maksymalna liczba wywołań w oknie czasowym
* @var int
*/
protected const RATE_LIMIT = 100;
/**
* Okno czasowe dla rate limit (w sekundach)
* @var int
*/
protected const RATE_WINDOW = 3600;
/**
* Sprawdza klucz API oraz limit wywołań (rate limit)
*
* @param WP_REST_Request $request Obiekt żądania REST API
*
* @return true|WP_Error
* - true jeśli klucz API poprawny i limit nie przekroczony
* - WP_Error w przypadku niepoprawnego klucza lub przekroczenia limitu
*/
public static function checkApiKey(WP_REST_Request $request) {
$key = (string) $request->get_param('api_key');
if (!hash_equals(static::API_KEY, $key)) {
return new WP_Error('forbidden', 'Nieprawidłowy klucz API', ['status' => 403]);
}
$transient_name = 'rate_' . md5($key);
$history = get_transient($transient_name) ?: [];
$now = time();
$history = array_filter($history, fn($t) => $t > $now - static::RATE_WINDOW);
if (count($history) >= static::RATE_LIMIT) {
return new WP_Error(
'rate_limit',
'Przekroczono limit ' . static::RATE_LIMIT . ' wywołań na ' . (static::RATE_WINDOW / 3600) . 'h',
['status' => 429]
);
}
$history[] = $now;
set_transient($transient_name, $history, static::RATE_WINDOW);
return true;
}
/**
* Zwraca dane w formacie REST API (JSON)
*
* @param mixed $data Dane do zwrócenia
* @return \WP_REST_Response
*/
protected static function respond($data) {
return rest_ensure_response($data);
}
/**
* Rejestruje endpoint REST API
*
* @param string $url Ścieżka endpointu, np. '/wykonawcy'
* @param string $callback Nazwa metody w klasie obsługującej endpoint
* @param string|array $method Typ żądania HTTP (domyślnie GET)
* - WP_REST_Server::READABLE → GET
* - WP_REST_Server::CREATABLE → POST
* - WP_REST_Server::EDITABLE → PUT/PATCH
* - WP_REST_Server::DELETABLE → DELETE
*
* @return void
*/
protected static function registerRoute(
string $url,
string $callback,
string|array $method = WP_REST_Server::READABLE
) {
register_rest_route('apr/v3', $url, [
'methods' => $method,
'callback' => [static::class, $callback],
'permission_callback' => [static::class, 'checkApiKey']
]);
}
/**
* Rejestracja endpointów przez klasę potomną
*
* @return void
*/
abstract public static function register(): void;
}
/**
* Klasa implementująca endpointy dla wykonawców
*/
class Wykonawcy extends AbstractApi {
/**
* Statyczna tablica przechowująca wykonawców (symulacja bazy)
* @var array<int, array{id: int, nazwa: string}>
*/
private static array $wykonawcy = [
['id' => 1, 'nazwa' => 'Metallica'],
['id' => 2, 'nazwa' => 'Queen']
];
/**
* Rejestracja endpointów REST API
*
* @return void
*/
public static function register(): void {
self::registerRoute('/wykonawcy', 'endpointLista');
self::registerRoute('/wykonawcy/add', 'endpointAdd', WP_REST_Server::CREATABLE);
}
/**
* Endpoint GET /wykonawcy
* Zwraca listę wszystkich wykonawców
*
* @param WP_REST_Request $request Obiekt żądania
* @return \WP_REST_Response Lista wykonawców
*/
public static function endpointLista(WP_REST_Request $request) {
return self::respond(self::$wykonawcy);
}
/**
* Endpoint POST /wykonawcy/add
* Dodaje nowego wykonawcę (symulacja w tablicy statycznej)
*
* @param WP_REST_Request $request Obiekt żądania
* @return \WP_REST_Response|WP_Error
* - WP_REST_Response z nowym wykonawcą
* - WP_Error jeśli pole "nazwa" jest puste
*/
public static function endpointAdd(WP_REST_Request $request) {
$name = sanitize_text_field($request->get_param('nazwa'));
if (empty($name)) {
return new WP_Error('invalid_data', 'Pole "nazwa" nie może być puste', ['status' => 400]);
}
$new_id = end(self::$wykonawcy)['id'] + 1;
$nowy = ['id' => $new_id, 'nazwa' => $name];
self::$wykonawcy[] = $nowy;
return self::respond([
'success' => true,
'wykonawca' => $nowy
]);
}
}
/**
* Akcja inicjalizująca REST API
*/
add_action('rest_api_init', function () {
\API\Wykonawcy::register();
});
Abstrakcyjna klasa bazowa: AbstractApi
Abstrakcyjna klasa AbstractApi jest fundamentem naszego API. Zawiera wszystkie mechanizmy wspólne dla wszystkich endpointów:
-
API Key – weryfikacja przy każdym żądaniu REST
-
Rate limiting – sliding window, aby ograniczyć liczbę wywołań w określonym czasie
-
Helper do odpowiedzi –
respond()generuje obiektWP_REST_Response -
Helper do rejestracji endpointów –
registerRoute()
Kluczowe metody
checkApiKey(WP_REST_Request $request)
public static function checkApiKey(WP_REST_Request $request)
-
Sprawdza, czy w żądaniu REST API przesłano poprawny klucz API.
-
Weryfikuje również, czy nie przekroczono limit wywołań (100 wywołań na godzinę w przykładzie).
-
Zwraca
true, jeśli wszystko jest w porządku, lubWP_Errorw przypadku błędu.
Dzięki tej metodzie każdy endpoint automatycznie korzysta z bezpiecznej autoryzacji i ochrony przed nadmiernym ruchem.
respond($data)
protected static function respond($data)
-
Ułatwia zwracanie danych w formacie JSON (
WP_REST_Response). -
Dzięki temu nie trzeba za każdym razem ręcznie tworzyć obiektów REST Response.
registerRoute(string $url, string $callback, string|array $method = WP_REST_Server::READABLE)
-
Rejestruje endpoint w WordPressie w ramach
rest_api_init. -
Obsługuje różne typy żądań: GET, POST, PUT/PATCH, DELETE.
-
Automatycznie przypisuje
checkApiKeyjakopermission_callback.
self::registerRoute('/wykonawcy', 'endpointLista');
Endpointy wykonawców: klasa Wykonawcy
Wykonawcy dziedziczy po AbstractApi i implementuje dwa podstawowe endpointy:
-
GET
/wykonawcy– zwraca listę wszystkich wykonawców -
POST
/wykonawcy/add– dodaje nowego wykonawcę (symulacja w tablicy PHP)
Endpoint GET /wykonawcy
public static function endpointLista(WP_REST_Request $request)
-
Zwraca statyczną tablicę wykonawców.
-
W pełnej implementacji można podłączyć tu bazę danych.
-
Odpowiedź jest automatycznie opakowana w
WP_REST_Response.
Przykładowa odpowiedź JSON:
[
{"id": 1, "nazwa": "Metallica"},
{"id": 2, "nazwa": "Queen"}
]
Endpoint POST /wykonawcy/add
public static function endpointAdd(WP_REST_Request $request)
-
Pobiera parametr
nazwaz żądania POST i waliduje go. -
Jeśli pole jest puste – zwraca
WP_Errorz kodem 400. -
Tworzy nowy wpis w tablicy statycznej (symulacja dodania do bazy).
-
Zwraca nowy obiekt wykonawcy wraz z ID.
Przykładowa odpowiedź JSON:
{
"success": true,
"wykonawca": {
"id": 3,
"nazwa": "Nirvana"
}
}
Podsumowanie
Dzięki takiemu podejściu:
-
Kod jest modularny – nowe endpointy można dodawać w klasach potomnych.
-
API jest bezpieczne – każdy request jest weryfikowany pod kątem klucza i limitu wywołań.
-
Kodu jest czytelny i dobrze udokumentowany dzięki PHPDoc, co ułatwia dalszą rozbudowę i integrację z IDE.
-
Można łatwo podłączyć bazę danych w przyszłości, zachowując mechanizmy bezpieczeństwa i odpowiedzi w JSON.
Tour Script