PHPackages                             nilanjan-k/api-response-formatter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. nilanjan-k/api-response-formatter

ActiveLibrary[HTTP &amp; Networking](/categories/http)

nilanjan-k/api-response-formatter
=================================

A production-ready Laravel package for standardized, consistent JSON API responses.

v1.0.0(1w ago)00MITPHP ^8.1

Since Jun 1Pushed 1w agoCompare

[ Source](https://github.com/nilanjan-k/api-response-formatter)[ Packagist](https://packagist.org/packages/nilanjan-k/api-response-formatter)[ RSS](/packages/nilanjan-k-api-response-formatter/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (7)Versions (2)Used By (0)

api-response-formatter
======================

[](#api-response-formatter)

[![Latest Version on Packagist](https://camo.githubusercontent.com/82c1fdc22dee5628aa75e489d9afe915962715168c9182104179ffa4fef2e8c1/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e696c616e6a616e2d6b2f6170692d726573706f6e73652d666f726d61747465722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nilanjan-k/api-response-formatter)[![PHP Version](https://camo.githubusercontent.com/bf0f3da73563082da1c1b5ba52c7aabefd27d6aa7b46fbc3802412a7c00cffe5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253545382e312d626c75653f7374796c653d666c61742d737175617265)](https://php.net)[![Laravel](https://camo.githubusercontent.com/e4b4417608280e3c296e76e86068149c541c71c507db6e2cceafdc006bd0e161/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31302532302537432532303131253230253743253230313225323025374325323031332d6f72616e67653f7374796c653d666c61742d737175617265)](https://laravel.com)[![Tests](https://camo.githubusercontent.com/7c08974287f3e98f7fe93abcc877998db181866ca92e6ef2da0cd4861ac72938/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6e696c616e6a616e2d6b2f6170692d726573706f6e73652d666f726d61747465722f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/nilanjan-k/api-response-formatter/actions)[![License](https://camo.githubusercontent.com/3a0ecdcf206ecbd31cbe7abcb9a9a0049f327c62b786548420f5d1613e6702b8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6e696c616e6a616e2d6b2f6170692d726573706f6e73652d666f726d61747465723f7374796c653d666c61742d737175617265)](LICENSE)

A production-ready Laravel package that gives **every** API response — success, error, validation failure, paginated list, or unhandled exception — the **same predictable JSON envelope**. Frontend and mobile clients always know exactly what shape to expect, regardless of which controller or service produced it.

```
{
  "status": true,
  "code":   200,
  "message": "Users fetched successfully.",
  "data":   [ ],
  "errors": null,
  "meta":   null
}
```

---

Table of Contents
-----------------

[](#table-of-contents)

- [Requirements](#requirements)
- [Installation](#installation)
    - [From Packagist (normal)](#from-packagist-normal)
    - [Local development / path repository](#local-development--path-repository)
- [Configuration](#configuration)
    - [Publishing the config file](#publishing-the-config-file)
    - [Config options](#config-options)
- [Usage](#usage)
    - [Option A — Facade](#option-a--facade)
    - [Option B — HasApiResponse trait](#option-b--hasapiresponse-trait)
    - [Option C — Global helper functions](#option-c--global-helper-functions)
- [Available methods](#available-methods)
- [Response shape reference](#response-shape-reference)
- [Paginated responses](#paginated-responses)
- [Exception handler integration](#exception-handler-integration)
    - [Laravel 11 and 12 (bootstrap/app.php)](#laravel-11-and-12-bootstrapappphp)
    - [Laravel 10 (app/Exceptions/Handler.php)](#laravel-10-appexceptionshandlerphp)
    - [Exceptions handled automatically](#exceptions-handled-automatically)
- [Macro support](#macro-support)
- [BaseResource](#baseresource)
- [Localization / i18n](#localization--i18n)
- [Security considerations](#security-considerations)
- [Testing](#testing)
- [Contributing](#contributing)
- [Changelog](#changelog)
- [License](#license)

---

Requirements
------------

[](#requirements)

DependencyVersionPHP`^8.1`Laravel`10`, `11`, `12`, or `13`---

Installation
------------

[](#installation)

### From Packagist (normal)

[](#from-packagist-normal)

```
composer require nilanjan-k/api-response-formatter
```

Laravel's **package auto-discovery** registers the service provider and the `ApiResponse` facade alias automatically. No manual edits to `config/app.php`are needed.

### Local development / path repository

[](#local-development--path-repository)

If you are working on the package itself alongside a test application, tell Composer where to find it via a `path` repository entry — no Packagist publishing required.

**1. Add the path repository to your Laravel app's `composer.json`:**

```
{
    "repositories": [
        {
            "type": "path",
            "url": "../api-response-formatter",
            "options": {
                "symlink": true
            }
        }
    ]
}
```

**2. Require the package:**

```
composer require nilanjan-k/api-response-formatter:@dev
```

Composer creates a symlink from `vendor/nilanjan-k/api-response-formatter` to your local package folder, so every edit you make is reflected instantly — no `composer update` needed.

**3. Verify auto-discovery ran:**

```
php artisan package:discover --ansi
```

You should see `NilanjanK\ApiResponseFormatter\ApiResponseServiceProvider`listed as discovered.

---

Configuration
-------------

[](#configuration)

### Publishing the config file

[](#publishing-the-config-file)

```
# Publish the config file
php artisan vendor:publish --tag=api-response-config

# Publish the language files (optional — for customising default messages)
php artisan vendor:publish --tag=api-response-lang
```

The config file is published to `config/api-response.php`. The lang files are published to `lang/vendor/api-response/`.

### Config options

[](#config-options)

KeyTypeDefaultDescription`include_meta``bool``true`Include a `"meta"` key in every response. `null` for non-paginated responses; populated for paginated responses.`include_timestamp``bool``false`Append `"timestamp"` (ISO-8601) to every response.`include_request_id``bool``false`Append `"request_id"` to every response. Uses the incoming `X-Request-Id` header **only if it is a valid UUID v4**; otherwise generates a fresh one.`debug``bool``false`When `true` **and** `APP_DEBUG=true`, include exception details in 500 responses. Stack-frame arguments are always stripped before serialisation. **Leave `false` in production.**`default_messages``array``[]`Override the default message for any HTTP status code. Falls back to `lang/en/messages.php` for missing codes.---

Usage
-----

[](#usage)

Three styles are available. Pick whichever fits your team's conventions — they all produce identical JSON.

### Option A — Facade

[](#option-a--facade)

```
use NilanjanK\ApiResponseFormatter\Facades\ApiResponse;

class UserController extends Controller
{
    public function index(): JsonResponse
    {
        return ApiResponse::success(User::all(), 'Users fetched successfully.');
    }

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

        return ApiResponse::created($user, 'User created successfully.');
    }

    public function update(UpdateUserRequest $request, User $user): JsonResponse
    {
        $user->update($request->validated());

        return ApiResponse::success($user, 'User updated.');
    }

    public function destroy(User $user): JsonResponse
    {
        $user->delete();

        return ApiResponse::noContent();
    }
}
```

### Option B — HasApiResponse trait

[](#option-b--hasapiresponse-trait)

Add `use HasApiResponse` directly in a controller. No static calls or facade imports needed.

```
use NilanjanK\ApiResponseFormatter\Traits\HasApiResponse;

class PostController extends Controller
{
    use HasApiResponse;

    public function index(): JsonResponse
    {
        return $this->success(Post::paginate(15), 'Posts listed.');
    }

    public function show(Post $post): JsonResponse
    {
        return $this->success($post, 'Post retrieved.');
    }

    public function store(StorePostRequest $request): JsonResponse
    {
        return $this->created(
            Post::create($request->validated()),
            'Post created.'
        );
    }

    public function destroy(Post $post): JsonResponse
    {
        $post->delete();

        return $this->noContent();
    }
}
```

### Option C — Global helper functions

[](#option-c--global-helper-functions)

Four global functions are auto-loaded via `helpers.php`. They are available anywhere — middleware, jobs, service classes, Artisan commands.

```
// Resolve the manager instance and chain any method
api_response()->success($data);
api_response()->notFound('Item not found.');

// Named shortcut helpers
api_success($data, 'Done.');           // → 200
api_error('Something broke.', 500);    // → any error code
api_paginated($paginator, 'Listed.');  // → 200 with meta
```

---

Available methods
-----------------

[](#available-methods)

MethodHTTP code`status``success($data, $message, $code = 200)`200`true``created($data, $message)`201`true``noContent()`204—`paginated($paginator, $message, $code = 200)`200`true``error($message, $code = 400, $errors)`any`false``validationError($errors, $message)`422`false``unauthorized($message)`401`false``forbidden($message)`403`false``notFound($message)`404`false``serverError($message, $errors)`500`false`All `$message` and `$errors` parameters are optional. When `$message` is omitted the package looks up a default from `config/api-response.php`(`default_messages`) and falls back to `lang/en/messages.php`.

---

Response shape reference
------------------------

[](#response-shape-reference)

Every response (except `noContent`) always contains the same six keys so clients can write a single deserialiser.

```
{
  "status":     bool          — true on success, false on error
  "code":       int           — mirrors the HTTP status code
  "message":    string        — human-readable description
  "data":       mixed|null    — payload on success, null on error
  "errors":     mixed|null    — error details on failure, null on success
  "meta":       object|null   — pagination info (paginated only), otherwise null
}

```

**Optional fields** (enabled via config):

```
  "timestamp":  string   — ISO-8601 datetime  (include_timestamp = true)
  "request_id": string   — UUID v4             (include_request_id = true)

```

### Success — 200

[](#success--200)

```
{
  "status":  true,
  "code":    200,
  "message": "Users fetched successfully.",
  "data":    [{ "id": 1, "name": "Alice" }],
  "errors":  null,
  "meta":    null
}
```

### Created — 201

[](#created--201)

```
{
  "status":  true,
  "code":    201,
  "message": "User created successfully.",
  "data":    { "id": 42, "name": "Bob" },
  "errors":  null,
  "meta":    null
}
```

### Validation error — 422

[](#validation-error--422)

```
{
  "status":  false,
  "code":    422,
  "message": "The given data was invalid.",
  "data":    null,
  "errors":  {
    "email": ["The email field is required."],
    "name":  ["The name must be at least 3 characters."]
  },
  "meta":    null
}
```

### Not found — 404

[](#not-found--404)

```
{
  "status":  false,
  "code":    404,
  "message": "The requested resource was not found.",
  "data":    null,
  "errors":  null,
  "meta":    null
}
```

### Server error — 500 (with `debug = true` and `APP_DEBUG = true`)

[](#server-error--500-with-debug--true-and-app_debug--true)

```
{
  "status":  false,
  "code":    500,
  "message": "An internal server error occurred. Please try again later.",
  "data":    null,
  "errors":  {
    "exception": "RuntimeException",
    "message":   "Something exploded.",
    "file":      "/var/www/app/Services/PaymentService.php",
    "line":      84,
    "trace":     [ ... ]
  },
  "meta":    null
}
```

> **Note:** Stack-frame `args` are **always** removed from the trace before serialisation, even in debug mode, to prevent leaking passwords, tokens, or sensitive model state. See [Security considerations](#security-considerations).

---

Paginated responses
-------------------

[](#paginated-responses)

Pass any `AbstractPaginator` instance — including the result of Eloquent's `paginate()` or `simplePaginate()`:

```
public function index(): JsonResponse
{
    $users = User::paginate(15);

    return ApiResponse::paginated($users, 'Users listed.');
    // or: $this->paginated($users, 'Users listed.');
    // or: api_paginated($users, 'Users listed.');
}
```

Response:

```
{
  "status":  true,
  "code":    200,
  "message": "Users listed.",
  "data": [
    { "id": 1, "name": "Alice" },
    { "id": 2, "name": "Bob"   }
  ],
  "errors": null,
  "meta": {
    "current_page": 1,
    "per_page":     15,
    "total":        100,
    "last_page":    7,
    "from":         1,
    "to":           15
  }
}
```

`simplePaginate()` / `CursorPaginator` do not support `total` and `last_page` — those fields will be `null` in the meta block.

---

Exception handler integration
-----------------------------

[](#exception-handler-integration)

The `HandlesApiExceptions` trait automatically converts unhandled exceptions into the standard JSON envelope. Wire it up once and every unhandled exception your application throws will return a consistent error response.

### Laravel 11 and 12 (`bootstrap/app.php`)

[](#laravel-11-and-12-bootstrapappphp)

```
