Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Smart Response Laravel Package

quonain/smart-response

SmartResponse is a Laravel package that returns JSON API responses or Blade/Inertia views from the same controller method, auto-detecting request type (Accept header, /api routes, bearer tokens). Includes pagination, response shortcuts, macros, caching, and meta enrichment.

View on GitHub
Deep Wiki
Context7

SmartResponse

Latest Version on Packagist License PHP Version

SmartResponse is a production-ready Laravel package that returns API JSON or Blade / Inertia web views from the same controller method — with automatic request-type detection.


Table of contents


Features

Category Capabilities
Detection Accept header, expectsJson(), /api/* routes, Bearer tokens (Sanctum / Passport)
API Standard JSON envelope, optional XML, validation errors, exception handler
Web Blade views, redirects, session flash, optional toast
Pagination Length-aware, simple, cursor paginators + API Resources
DX Trait, Facade, global helpers, response()->smart* macros
HTTP shortcuts created, noContent, notFound, unauthorized, forbidden
Meta Auto timestamp, request_id, optional api_version on API responses
Extras Inertia.js, Livewire, i18n, caching, logging, events, OpenAPI examples
Framework Laravel 10 · 11 · 12 · 13 · PHP 8.2+

Requirements

  • PHP ^8.2
  • Laravel ^10.0 · ^11.0 · ^12.0 · ^13.0

Installation

composer require quonain/smart-response

Or pin the latest 1.x release:

composer require quonain/smart-response:^1.1

Laravel auto-discovers the service provider — no manual registration.

Publish assets

# Configuration
php artisan vendor:publish --tag=smart-response-config

# Translations
php artisan vendor:publish --tag=smart-response-lang

Packagist: After a new release, open your package page and click Update if Composer does not see the latest tag yet. Enable the GitHub hook under package settings for automatic sync.


Quick start

1. Add the trait

use Illuminate\Http\Request;
use Quonain\SmartResponse\Traits\HasSmartResponse;

class UserController extends Controller
{
    use HasSmartResponse;

    public function index(Request $request)
    {
        $users = User::paginate(15);

        return $this->smartResponse(
            request: $request,
            data: UserResource::collection($users),
            view: 'users.index',
            message: 'users.fetched', // translation key (optional)
        );
    }

    public function store(Request $request)
    {
        $user = User::create($request->validated());

        return $this->smartCreated($user, 'users.created');
    }
}
Request type Result
API (Accept: application/json, /api/*, Bearer token, …) Standard JSON
Web (text/html, normal browser) Blade view users.index with $data, $message, …

2. Default JSON shape

{
  "success": true,
  "message": "Users fetched successfully",
  "data": [],
  "meta": {
    "timestamp": "2026-05-21T12:00:00+00:00",
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "current_page": 1,
    "per_page": 15,
    "total": 100
  },
  "errors": null
}

How API vs Web is detected

SmartResponse treats a request as API when any of these match (configurable in config/smart-response.php):

  1. Accept contains application/json or application/vnd.api+json
  2. Accept contains application/xml or text/xml
  3. Route matches api/* or configured prefixes (api by default)
  4. Laravel expectsJson() is true (AJAX, etc.)
  5. Authorization: Bearer … is present (detection.bearer_as_api — ideal for Sanctum / Passport SPA or mobile apps)

Otherwise the request is handled as Web (view or redirect).


Usage

Unified smartResponse()

return $this->smartResponse(
    request: $request,
    data: $data,
    view: 'users.index',
    viewData: ['title' => 'Users'],
    message: 'Success',
    success: true,
    errors: null,
    meta: ['custom' => 'value'],
    status: 200,
    route: 'users.index',       // web redirect
    routeParameters: [],
    format: null,               // auto: json | xml
    flash: true,
    toast: false,
    cacheKey: null,
    cacheTtl: null,
    headers: ['X-Custom' => '1'],
    inertiaComponent: 'Users/Index',
    useInertia: false,
    useLivewire: false,
);

HTTP shortcuts

Trait method Facade / Manager Status Use case
smartSuccess() SmartResponse::success() 200 OK with data
smartCreated() SmartResponse::created() 201 Resource created
smartNoContent() SmartResponse::noContent() 204 Delete / empty OK
smartError() SmartResponse::error() 4xx/5xx Generic error
smartNotFound() SmartResponse::notFound() 404 Missing resource
smartUnauthorized() SmartResponse::unauthorized() 401 Not logged in
smartForbidden() SmartResponse::forbidden() 403 No permission
smartValidationError() SmartResponse::validationError() 422 Form / API validation
return $this->smartSuccess($users, 'Users loaded');
return $this->smartCreated($user, 'users.created');
return $this->smartNoContent();
return $this->smartNotFound('error.not_found');
return $this->smartUnauthorized();
return $this->smartForbidden('error.forbidden');
return $this->smartValidationError($validator->errors());

Facade & global helpers

use Quonain\SmartResponse\Facades\SmartResponse;

SmartResponse::success($data, 'Done');
SmartResponse::created($data, 'Created');
SmartResponse::notFound('Not found');

// Global helpers (no trait required)
smart_response(request: $request, data: $users, view: 'users.index');
smart_created($user, 'users.created');
smart_not_found('error.not_found');
smart_rate_limit_response(retryAfter: 60);

Response macros

response()->smart($data, 'OK');
response()->smartSuccess($data, 'Saved');
response()->smartError('Failed', ['code' => 'X'], 400);
response()->smartCreated($data, 'Created');
response()->smartNotFound('Not found');

Pagination

Length-aware — pass a paginator; meta keys are merged automatically:

return $this->smartResponse(
    request: $request,
    data: User::paginate(20),
    view: 'users.index',
);

Cursor — works with cursorPaginate():

return $this->smartResponse(
    request: $request,
    data: User::orderBy('id')->cursorPaginate(15),
);

Meta includes: per_page, path, next_cursor, prev_cursor, has_more.

API Resources & XML

// API Resource collection
return $this->smartResponse(
    request: $request,
    data: UserResource::collection($users),
    view: 'users.index',
);

// Force or auto-detect XML
return $this->smartResponse(request: $request, data: $users, format: 'xml');

API meta enrichment

Enabled by default (meta.enabled in config). Every API response can include:

Meta key Source
timestamp Current time (ISO 8601)
request_id X-Request-Id header or auto UUID
api_version X-API-Version header or meta.api_version config
// config/smart-response.php
'meta' => [
    'enabled' => true,
    'include_timestamp' => true,
    'include_request_id' => true,
    'request_id_header' => 'X-Request-Id',
    'include_api_version' => true,
    'api_version' => '1.0',
],

Rate limiting

Returns a standard error JSON with Retry-After header:

// Uses config defaults (429 + retry_after_seconds)
return smart_rate_limit_response();

// Custom message and seconds
return smart_rate_limit_response('Slow down', 120);

Caching (API)

Enable in config, then cache GET API responses:

return $this->smartResponse(
    request: $request,
    data: $expensiveData,
    cacheKey: 'users.index',
    cacheTtl: 120,
);

Without cacheKey, a hash of the full URL + Accept header is used.

Web redirect with flash & toast

return $this->smartResponse(
    request: $request,
    message: 'User created',
    route: 'users.index',
    toast: true,
    status: 201,
);

Exception handling (API)

Register in bootstrap/app.php (Laravel 11+):

use Quonain\SmartResponse\Exceptions\Handler\SmartResponseExceptionHandler;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (Throwable $e, $request) {
        return app(SmartResponseExceptionHandler::class)->render($request, $e);
    });
})

API requests receive the same JSON envelope; web requests fall through to Laravel’s default handling.


Configuration

Publish config/smart-response.php and adjust:

Key Description
api.* JSON keys: success, message, data, meta, errors
detection.* JSON/XML accepts, route prefixes, bearer_as_api
meta.* Timestamp, request ID, API version injection
default_format json or xml
status_codes.* Defaults for 200, 201, 204, 401, 403, 404, 422, 429, 500
web.* Flash / toast session keys, default redirect route
inertia.enabled Inertia.js adapter
livewire.enabled Livewire hooks
locale.enabled Translate message keys via lang files
cache.enabled Cache GET API responses
logging.enabled Log each response
events.enabled SmartResponsePreparing / SmartResponsePrepared
rate_limit.* 429 message and retry_after_seconds
graphql.enabled GraphQL response Accept detection

Multi-language messages

return $this->smartResponse(message: 'users.fetched');
// → lang/vendor/smart-response/en/messages.php

Built-in keys include: users.fetched, users.created, error.not_found, error.unauthorized, error.forbidden, error.rate_limit, and more.

Inertia.js

// config/smart-response.php
'inertia' => ['enabled' => true],

return $this->smartResponse(
    request: $request,
    data: $users,
    inertiaComponent: 'Users/Index',
    useInertia: true,
);

Middleware

Alias: smart.response (enabled by default)

Route::middleware('smart.response')->group(function () {
    // ...
});

Events

use Quonain\SmartResponse\Events\SmartResponsePreparing;
use Quonain\SmartResponse\Events\SmartResponsePrepared;

Event::listen(SmartResponsePreparing::class, fn ($e) => /* mutate payload */);
Event::listen(SmartResponsePrepared::class, fn ($e) => /* inspect response */);

OpenAPI / Swagger

use Quonain\SmartResponse\Support\OpenApiExample;

OpenApiExample::successExample();
OpenApiExample::errorExample();

Testing

composer install
composer test

Package structure

smart-response/
├── config/smart-response.php
├── lang/en/messages.php
├── src/
│   ├── Contracts/
│   ├── Detectors/          # API vs Web detection
│   ├── DTO/
│   ├── Formatters/         # JSON, XML
│   ├── Builders/
│   ├── Services/
│   ├── Traits/             # HasSmartResponse
│   ├── Facades/
│   ├── Events/
│   ├── Exceptions/
│   ├── Http/Middleware/
│   ├── Macros/
│   └── Support/            # MetaEnricher, Pagination, i18n, …
├── tests/
├── examples/
└── README.md

Changelog

See CHANGELOG.md for version history (1.1.0 — HTTP shortcuts, meta enrichment, cursor pagination, Bearer detection).


Contributing

See CONTRIBUTING.md.


License

MIT © Quonain Ejaz. See LICENSE.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky