JSON response helper
Beginner5 min read·fw-04-006
Concept
JSON response helper is a convenience layer for the most common API response pattern. Instead of manually constructing a Response with JSON body and content-type header every time, a helper encapsulates it. It also handles PHP encoding options, error handling, and status code conventions.
What a JSON helper adds:
- Sets
Content-Type: application/json; charset=UTF-8automatically. - Handles
json_encode()errors gracefully. - Provides semantic status helpers:
Response::ok(),Response::created(),Response::unprocessable(). - Can standardize response envelope structure:
{data: ..., meta: ...}or{error: ..., code: ...}.
json_encode() options:
JSON_UNESCAPED_UNICODE: Don't escape multibyte characters (é, ü, etc.) to\uXXXX.JSON_UNESCAPED_SLASHES: Don't escape/to\/. Cleaner URLs in JSON.JSON_THROW_ON_ERROR: ThrowJsonExceptionon failure instead of returning false.JSON_PRETTY_PRINT: Human-readable output (dev only — larger payload).
API envelope pattern: Wrapping all responses in a consistent structure:
json
{"data": {...}, "meta": {"page": 1}}
{"errors": [{"field": "email", "message": "Required"}]}Helps API clients handle responses uniformly.
JSONP (rare today): Response::jsonp($callback, $data) — wraps JSON in a callback function for cross-origin requests in old browsers. Not needed with modern CORS.
Code Example
php
<?php
namespace Framework\Http;
class JsonResponse extends Response
{
public function __construct(mixed $data, int $status = 200, array $extraHeaders = [])
{
$body = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
parent::__construct(
$body,
$status,
array_merge(['Content-Type' => 'application/json; charset=UTF-8'], $extraHeaders)
);
}
// Semantic helpers
public static function ok(mixed $data, array $meta = []): static
{
return new static(empty($meta) ? $data : ['data' => $data, 'meta' => $meta]);
}
public static function created(mixed $data): static
{
return new static(['data' => $data], 201);
}
public static function noContent(): static
{
return new static(null, 204);
}
public static function error(string $message, int $status = 400, array $errors = []): static
{
$body = ['error' => $message];
if (!empty($errors)) $body['errors'] = $errors;
return new static($body, $status);
}
public static function validationError(array $errors): static
{
return static::error('Validation failed', 422, $errors);
}
public static function unauthorized(string $message = 'Unauthenticated'): static
{
return static::error($message, 401);
}
public static function forbidden(string $message = 'Forbidden'): static
{
return static::error($message, 403);
}
public static function notFound(string $message = 'Not found'): static
{
return static::error($message, 404);
}
}
// Usage in controllers/handlers
class UserController
{
public function index(): JsonResponse
{
$users = User::all();
return JsonResponse::ok($users->toArray(), ['total' => $users->count()]);
}
public function show(int $id): JsonResponse
{
$user = User::find($id);
if (!$user) return JsonResponse::notFound('User not found');
return JsonResponse::ok($user->toArray());
}
public function store(Request $request): JsonResponse
{
$user = User::create($request->all());
return JsonResponse::created($user->toArray());
}
}