ApiResponse - viames/pair GitHub Wiki
Pair framework: 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
Main methods (deep dive)
1) ApiResponse::respond(array|stdClass|null $data, int $httpCode = 200): void
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.
2) ApiResponse::error(string $errorCode, array $extra = []): void
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',
]);
2.1) ApiResponse::errorResponse(string $errorCode, array $extra = []): ApiErrorResponse
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',
]);
2.2) ApiResponse::jsonResponse(mixed $data, int $httpCode = 200): JsonResponse
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::successResponse(?string $message = null): JsonResponse
Use successResponse() for lightweight acknowledgements that should still travel through the explicit v4 response path.
return ApiResponse::successResponse('Done');
3) ApiResponse::paginated(array $data, int $page, int $perPage, int $total): void
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](/viames/pair/wiki/'id'-=>-1],-['id'-=>-2);
ApiResponse::paginated($rows, $page, $perPage, $total);
3.1) ApiResponse::paginatedResponse(array $data, int $page, int $perPage, int $total): JsonResponse
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);
4) ApiResponse::success(?string $message = null): void
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');
5) ApiResponse::registerErrors(array $errors): void
Use registerErrors() to add application-specific error codes or override built-in ones intentionally.
ApiResponse::registerErrors([
'ORDER_ALREADY_SHIPPED' => [
'httpCode' => 409,
'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',
],
]);
Secondary behavior
ApiResponse::ERRORSis the built-in error-code dictionary.- 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.
Practical notes
- 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.
Common pitfalls
- 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.