PHPackages                             dantepiazza/laravel-api-response - 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. [API Development](/categories/api)
4. /
5. dantepiazza/laravel-api-response

ActiveLibrary[API Development](/categories/api)

dantepiazza/laravel-api-response
================================

A fluent, expressive API response builder for Laravel 10+

003PHP

Since May 24Pushed 2w agoCompare

[ Source](https://github.com/dantepiazza/laravel-api-response)[ Packagist](https://packagist.org/packages/dantepiazza/laravel-api-response)[ RSS](/packages/dantepiazza-laravel-api-response/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)DependenciesVersions (1)Used By (3)

dantepiazza/laravel-api-response
================================

[](#dantepiazzalaravel-api-response)

A fluent, expressive JSend-compliant JSON API response builder for Laravel 10+.

> Implements the [JSend specification](https://github.com/omniti-labs/jsend): every response carries a `status` of `success`, `fail`, or `error`, making frontend handling predictable and consistent by convention.

---

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

[](#installation)

```
composer require dantepiazza/laravel-api-response
```

The service provider and `ApiResponse` facade are auto-discovered via Laravel's package discovery. No additional setup required.

### Publish config (optional)

[](#publish-config-optional)

```
php artisan vendor:publish --tag=api-response-config
```

---

Usage
-----

[](#usage)

Three ways to use the package — all share the same singleton instance and are fully interchangeable:

```
// 1. Helper function
api()->success()->response();

// 2. Facade
use DantePiazza\LaravelApiResponse\Facades\ApiResponse;
ApiResponse::success()->response();

// 3. Dependency injection (recommended for testability)
use DantePiazza\LaravelApiResponse\ApiResponse;

class UserController extends Controller
{
    public function __construct(private ApiResponse $api) {}

    public function index(): JsonResponse
    {
        return $this->api->success($users, 'Users retrieved')->response();
    }
}
```

For a clean DI setup across all controllers, inject in the base `Controller`:

```
// app/Http/Controllers/Controller.php
abstract class Controller
{
    public function __construct(protected ApiResponse $api) {}
}
```

---

Response structure
------------------

[](#response-structure)

The envelope follows the JSend standard. The `code` field mirrors the HTTP status code and is always present in the body for clients that don't inspect headers.

### `success` — 2xx

[](#success--2xx)

```
{
    "status": "success",
    "code": 200,
    "message": "Users retrieved",
    "data": { ... }
}
```

`data` is always present. It will be `null` if nothing was provided.
`message` is optional for `success` and `fail`.

### `fail` — 4xx

[](#fail--4xx)

Client-side error. `data` describes what went wrong (e.g. validation errors).

```
{
    "status": "fail",
    "code": 422,
    "message": "Validation failed",
    "data": {
        "email": "The email field is required.",
        "password": "Minimum 8 characters."
    }
}
```

### `error` — 5xx

[](#error--5xx)

Server-side error. `message` is **required** by JSend. `data` is optional.

```
{
    "status": "error",
    "code": 500,
    "message": "Internal server error"
}
```

---

API Reference
-------------

[](#api-reference)

### 2xx — success

[](#2xx--success)

MethodHTTPNotes`success(mixed $data = null, string $message)`200Standard success`created(mixed $data = null, string $message)`201Resource created`accepted(mixed $data = null, string $message)`202Async / queued`noContent()`204No body### 4xx — fail

[](#4xx--fail)

MethodHTTPDefault message`badRequest(mixed $data = null, string $message)`400The request parameters are incorrect.`unauthorized(mixed $data = null, string $message)`401Unauthorized`forbidden(mixed $data = null, string $message)`403Forbidden`notFound(mixed $data = null, string $message)`404Not found`methodNotAllowed(mixed $data = null, string $message)`405Method not allowed`conflict(mixed $data = null, string $message)`409Conflict`validationError(mixed $data = null, string $message)`422Validation failed`tooManyRequests(mixed $data = null, string $message)`429Too many requests### 5xx — error

[](#5xx--error)

MethodHTTPDefault message`serverError(mixed $data = null, string $message)`500Internal server error`serviceUnavailable(mixed $data = null, string $message)`503Service unavailable### Generic setter

[](#generic-setter)

Use when you need full control, e.g. inside a macro:

```
api()->set(ApiResponse::STATUS_FAIL, 409, 'Already exists', $data);

// Status constants:
ApiResponse::STATUS_SUCCESS  // 'success'
ApiResponse::STATUS_FAIL     // 'fail'
ApiResponse::STATUS_ERROR    // 'error'
```

---

Data helpers
------------

[](#data-helpers)

### Merging extra data

[](#merging-extra-data)

```
api()->success()
     ->data(['token' => $token, 'expires_in' => 3600])
     ->response();
```

Multiple `->data()` calls merge into the same array.

### Message-only override

[](#message-only-override)

```
api()->success()->message('Custom message')->response();
```

### Validation errors

[](#validation-errors)

Pass errors directly as `$data` — they land in `data` per the JSend spec:

```
api()->validationError('Validation failed', $validator->errors()->toArray())->response();
```

```
{
    "status": "fail",
    "code": 422,
    "message": "Validation failed",
    "data": {
        "email": ["The email field is required."],
        "name":  ["The name must be at least 3 characters."]
    }
}
```

---

Pagination
----------

[](#pagination)

### Laravel paginator (automatic)

[](#laravel-paginator-automatic)

Pass a `LengthAwarePaginator` directly — all fields are extracted automatically:

```
$users = User::paginate(15);

return api()->success()
            ->records($users)
            ->response();
```

### Manual array / Collection

[](#manual-array--collection)

```
return api()->success()
            ->records($users, total: 120, page: 2, pageSize: 15)
            ->response();
```

If `total` is omitted it defaults to `count($items)`.

### Pagination output

[](#pagination-output)

Both cases produce the same structure:

```
{
    "status": "success",
    "code": 200,
    "message": "Users retrieved",
    "data": {
        "results": [...],
        "pagination": {
            "total": 120,
            "per_page": 15,
            "current_page": 2,
            "last_page": 8,
            "from": 16,
            "to": 30,
            "links": {
                "prev": "https://example.com/api/users?page=1",
                "next": "https://example.com/api/users?page=3"
            }
        }
    }
}
```

---

Cookies
-------

[](#cookies)

```
api()->success()
     ->withCookie(cookie('token', $token, 60))
     ->withoutCookie('old_session')
     ->response();
```

---

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

[](#configuration)

After publishing the config you can rename any top-level JSON key to match an existing API contract:

```
// config/api-response.php
return [
    'keys' => [
        'status'  => 'status',   // default: 'status'
        'code'    => 'code',     // default: 'code'
        'message' => 'message',  // default: 'message'
        'data'    => 'data',     // default: 'data'
    ],
];
```

---

Macros
------

[](#macros)

Extend the class with custom shorthand methods in any service provider:

```
use DantePiazza\LaravelApiResponse\ApiResponse;

ApiResponse::macro('teapot', function () {
    return $this->set(ApiResponse::STATUS_FAIL, 418, "I'm a teapot");
});

// Then anywhere:
api()->teapot()->response();
```

---

Supported data types
--------------------

[](#supported-data-types)

`data()`, `records()`, and the `$data` argument of all shorthand methods accept:

- Plain `array`
- Any `object` (cast via `(array)`)
- `Illuminate\Support\Collection`
- `Illuminate\Http\Resources\Json\JsonResource`
- `Illuminate\Contracts\Pagination\LengthAwarePaginator` (in `records()` only)

---

Frontend — TypeScript model
---------------------------

[](#frontend--typescript-model)

The package ships `ApiResponse.ts`, a single TypeScript class that maps the JSend envelope into a typed object.

```
import { ApiResponse } from './ApiResponse';

const res = ApiResponse.from(await http.get('/api/users'));

if (res.isSuccess()) {
    console.log(res.data);      // unknown | null
    console.log(res.message);   // string

    // Paginated response
    const paged = res.records();
    if (paged) {
        paged.records       // User[]
        paged.total         // number
        paged.currentPage   // number
        paged.hasNextPage   // boolean
    }
}

if (res.isFail()) {
    // data contains the failure detail (e.g. validation errors)
    console.log(res.message, res.data);
}

if (res.isError()) {
    console.error(res.message);
}
```

Safe factory (returns `null` instead of throwing on invalid input):

```
const res = ApiResponse.tryFrom(raw); // ApiResponse | null
```

---

Testing
-------

[](#testing)

```
composer install
vendor/bin/phpunit
```

---

License
-------

[](#license)

MIT

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance63

Regular maintenance activity

Popularity0

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/14875983?v=4)[Dante Piazza Quiroga](/maintainers/dantepiazza)[@dantepiazza](https://github.com/dantepiazza)

---

Top Contributors

[![dantepiazza](https://avatars.githubusercontent.com/u/14875983?v=4)](https://github.com/dantepiazza "dantepiazza (2 commits)")

### Embed Badge

![Health badge](/badges/dantepiazza-laravel-api-response/health.svg)

```
[![Health](https://phpackages.com/badges/dantepiazza-laravel-api-response/health.svg)](https://phpackages.com/packages/dantepiazza-laravel-api-response)
```

###  Alternatives

[facebook/php-business-sdk

PHP SDK for Facebook Business

90923.5M35](/packages/facebook-php-business-sdk)[exsyst/swagger

A php library to manipulate Swagger specifications

35916.3M7](/packages/exsyst-swagger)[hubspot/api-client

Hubspot API client

24015.5M18](/packages/hubspot-api-client)[botman/driver-telegram

Telegram driver for BotMan

93452.6k6](/packages/botman-driver-telegram)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
