tbn/json-annotation-bundle
Symfony bundle that adds a @Json annotation for controllers to automatically return JSON responses. Wraps successful return arrays and exceptions into a consistent payload (success/data/message), with configurable keys, HTTP codes, and optional POST query echo/auth errors.
Installation:
composer require tbn/json-annotation-bundle:dev-master
Add to config/bundles.php (Laravel 5.4+):
return [
// ...
tbn\JsonAnnotationBundle\JsonAnnotationBundle::class => ['all' => true],
];
First Use Case:
Annotate a controller method with @Json() and return an array. The bundle automatically wraps the response in a standardized JSON structure:
use tbn\JsonAnnotationBundle\Configuration\Json;
class UserController extends Controller
{
/**
* @Route("/api/user", methods={"GET"})
* @Json()
*/
public function getUser()
{
return ['name' => 'John', 'email' => 'john@example.com'];
}
}
Output:
{
"success": true,
"data": {
"name": "John",
"email": "john@example.com"
}
}
config/packages/tbn_json_annotation.yaml (if auto-generated) or override in config/packages/dev/tbn_json_annotation.yaml.src/EventListener/ for custom pre-hook logic (e.g., token validation).Annotation-Driven Responses:
Use @Json() on methods returning arrays to enforce consistent API responses. Example:
/**
* @Json()
* @return array
*/
public function createUser(Request $request)
{
$validated = $request->validate(['name' => 'required']);
return User::create($validated);
}
Exception Handling: Let the bundle handle exceptions automatically. Customize error keys via config:
tbn_json_annotation:
exception_message_key: "error_details"
exception_code: 422
POST Data Echo:
Enable post_query_back to return request data in responses:
tbn_json_annotation:
post_query_back: true
post_query_key: "input"
Output:
{
"success": true,
"data": {...},
"input": {"name": "John"}
}
Authentication Errors: Disable default 401/403 responses and use JSON:
tbn_json_annotation:
enable_authentication_error: true
Output for Unauthenticated:
{
"success": false,
"message": "Unauthenticated."
}
@Json() methods in dedicated controllers (e.g., Api/UserController).api middleware for route grouping:
Route::prefix('api')->middleware('api')->group(function () {
Route::get('/users', [UserController::class, 'index']);
});
JsonPreHookEvent in unit tests:
$event = new JsonPreHookEvent($request, $response);
$this->assertTrue($event->isValid());
Annotation Parsing:
@Json() is on the method, not the class. The bundle uses Doctrine annotations under the hood.use tbn\JsonAnnotationBundle\Configuration\Json; at the top of the file.Non-Array Returns:
return (array) $this->userRepository->find($id);
Event Dispatching:
JsonPreHookEvent is dispatched before the method executes. Use it for early validation (e.g., token checks).@Json() is missing.Configuration Overrides:
tbn_json_annotation (not json_annotation). Typos here cause silent failures.php bin/console debug:container tbn_json_annotation to verify the bundle is loaded.JsonPreHookEvent:
public function onJsonPrehook(JsonPreHookEvent $event)
{
\Log::debug('Request:', $event->getRequest()->all());
}
dd($this->get('response')->getContent());
Custom Events:
Extend JsonPreHookEvent to add metadata:
class CustomJsonEvent extends JsonPreHookEvent
{
public function setCustomData(array $data) { ... }
}
Dispatch via:
$this->get('event_dispatcher')->dispatch(
'json.pre_hook',
new CustomJsonEvent($request, $response)
);
Response Transformers: Override the response logic by binding a custom service:
services:
tbn_json_annotation.response_transformer:
class: App\Service\CustomJsonTransformer
tags: ['tbn_json_annotation.transformer']
Authentication:
Replace default auth errors by implementing JsonAuthenticationListener:
public function onKernelException(GetResponseForExceptionEvent $event)
{
if ($event->getThrowable() instanceof AuthenticationException) {
$event->setResponse(new JsonResponse([
'success' => false,
'message' => 'Custom auth message'
]));
}
}
@Json() and validation logic.api middleware and version prefixes:
Route::prefix('api/v1')->group(...);
How can I help you explore Laravel packages today?