-
Notifications
You must be signed in to change notification settings - Fork 2
ApiResponse
Pair\Api\ApiResponse standardizes JSON responses for Pair API endpoints.
It provides:
- a built-in error registry (
ApiResponse::ERRORS) - runtime custom error registration
- small helpers for success, error, and paginated payloads
- explicit response builders for v4-style response returns
Use respond() for normal JSON responses with an explicit HTTP code.
use Pair\Api\ApiResponse;
ApiResponse::respond(['saved' => true], 201);This is the most flexible helper and the one you should use when the response shape is already known.
Important current behavior: the underlying Utilities::jsonResponse() treats empty payloads as no-content responses. In practice, ApiResponse::respond(null, 201) is emitted as HTTP 204, even if you passed 201.
Use error() for standardized API errors.
Current behavior:
- looks up custom registered errors first
- falls back to built-in
ERRORS - if the code is unknown, falls back to
INTERNAL_SERVER_ERROR - keeps only string keys from the
$extraarray before sending the payload
ApiResponse::error('BAD_REQUEST', [
'detail' => 'Missing field',
]);Validation example:
ApiResponse::error('INVALID_FIELDS', [
'errors' => [
'email' => 'The field email must be a valid email address',
'age' => 'The field age must be an integer',
],
]);Conflict example:
ApiResponse::error('CONFLICT', [
'detail' => 'Order is already paid',
]);Use errorResponse() when you want the same registry-driven error semantics as error(), but need to return an explicit response object instead of sending JSON immediately.
use Pair\Api\ApiResponse;
return ApiResponse::errorResponse('BAD_REQUEST', [
'detail' => 'Missing field',
]);Use jsonResponse() when you need the same payload semantics as respond(), but want to return an explicit response object instead of sending JSON immediately.
return ApiResponse::jsonResponse(['saved' => true], 201);JsonResponse can also carry scalar JSON values for replay or bridge cases, although arrays, objects, read models, and null remain the normal API shapes.
2.3) ApiResponse::localizedMessage(string $key, string|\Stringable|int|float|array|null $vars = null, ?string $default = null): string
Use localizedMessage() when API infrastructure needs a translated message but must remain safe in CLI tests or early bootstrap paths before the runtime translator can load database-backed locale data.
It delegates to Translator::safeDo() when available and falls back to Pair's built-in English messages or the supplied default.
The placeholder argument accepts the same value types as Translator::do(): a single string, Stringable, int, or float, or an array for multiple placeholders.
use Pair\Api\ApiResponse;
$message = ApiResponse::localizedMessage(
'ACTIVE_RECORD_CLASS_ERRORS',
3,
'ActiveRecord class errors: %s'
);Use successResponse() for lightweight acknowledgements that should still travel through the explicit v4 response path.
return ApiResponse::successResponse('Done');Use paginated() when the response must include standard paging metadata.
The output includes:
datameta.pagemeta.perPagemeta.totalmeta.lastPage
$page = max(1, (int)$this->request->query('page', 1));
$perPage = max(1, min(100, (int)$this->request->query('perPage', 20)));
$total = 187;
$rows = [['id' => 1], ['id' => 2]];
ApiResponse::paginated($rows, $page, $perPage, $total);Use paginatedResponse() when a list endpoint should return the standard data/meta envelope as an explicit response object.
return ApiResponse::paginatedResponse($rows, $page, $perPage, $total);Use this when you only need a simple success acknowledgment and do not care about a custom status code or payload shape.
ApiResponse::success('Done');Use registerErrors() to add application-specific error codes or override built-in ones intentionally.
ApiResponse::registerErrors([
'ORDER_ALREADY_SHIPPED' => [
'httpCode' => 409,
'messageKey' => 'ORDER_ALREADY_SHIPPED',
'message' => 'Order already shipped',
],
]);
ApiResponse::error('ORDER_ALREADY_SHIPPED', ['orderId' => 2241]);Another common pattern:
ApiResponse::registerErrors([
'PROFILE_NOT_COMPLETE' => [
'httpCode' => 409,
'message' => 'User profile is incomplete',
],
]);-
ApiResponse::ERRORSis the built-in error-code dictionary. - Error definitions can include
messageKeyfor localization andmessageas the safe fallback. - Mobile refresh failures use
AUTH_REFRESH_TOKEN_MISSINGandAUTH_REFRESH_TOKEN_INVALID. - Custom registered errors take precedence over built-in ones if keys collide.
-
ApiResponse::error()builds an explicit ApiErrorResponse internally before sending it, then preserves the legacy terminate-after-send behavior. -
respond(),success(), andpaginated()delegate to their explicit response builders before sending, then preserve the legacy terminate-after-send behavior. - Explicit response objects such as
JsonResponsedo not terminate execution by themselves; the v4 dispatcher decides when the request is complete.
- Prefer
error()over hand-written JSON error payloads so your API keeps a stable vocabulary. - Prefer
respond()when you need a custom status code such as201or204. - Prefer the
*Response()builders when you are migrating an endpoint toward explicit Pair v4 responses. - If the payload is
nullor otherwise empty, verify the final status code you want, because the current implementation promotes it to204. - Prefer
paginated()for list endpoints so clients always get the same metadata shape.
- Sending unknown error codes without registering them and expecting custom semantics.
- Echoing text or HTML before calling
ApiResponse::*, which breaks JSON responses. - Letting every endpoint invent its own error names instead of keeping a stable shared registry.
See also: API, JsonResponse, ApiErrorResponse, Request, Idempotency, CrudController.