Quick Start
Minimal router
use BetterRoute\Router\Router;
add_action('rest_api_init', function (): void {
Router::make('better-route', 'v1')
->get('/ping', fn (): array => ['pong' => true])
->meta([
'operationId' => 'systemPing',
'tags' => ['System'],
])
->permission(static fn (): bool => true)
;
});
Result:
- namespace:
better-route/v1 - endpoint:
GET /wp-json/better-route/v1/ping
Minimal resource (CPT)
use BetterRoute\Resource\Resource;
add_action('rest_api_init', function (): void {
Resource::make('articles')
->restNamespace('better-route/v1')
->sourceCpt('post')
->allow(['list', 'get'])
->fields(['id', 'title', 'slug', 'date'])
->filters(['status'])
->sort(['date', 'id'])
->register();
});
Minimal OpenAPI export endpoint
use BetterRoute\OpenApi\OpenApiRouteRegistrar;
OpenApiRouteRegistrar::register(
restNamespace: 'better-route/v1',
contractsProvider: static fn (): array => [
// typically merge router/resource contracts here
],
options: [
'title' => 'better-route API',
'version' => 'v0.4.0',
'serverUrl' => '/wp-json',
// Override the admin-only default (introduced in v0.3.0) to expose the doc:
// 'permissionCallback' => static fn (): bool => true,
]
);
The openapi.json endpoint is admin-only (manage_options) by default since v0.3.0. Pass permissionCallback if you need a different policy.
Common mistakes
- Forgetting
->register()on router/resource - Defining
restNamespacewithout vendor/version format (vendor/v1) - Assuming middleware auth replaces
permission_callback(it does not)
Validation checklist
- endpoint responds under
/wp-json/... - error payload includes
requestId - unknown query params fail with
400on resource list routes