PHPackages                             mediagone/symfony-easy-api - 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. mediagone/symfony-easy-api

ActiveLibrary[API Development](/categories/api)

mediagone/symfony-easy-api
==========================

Quickly build JSON API using plain Symfony controllers.

1.0.0(1y ago)23.4k↓100%1MITPHPPHP ^7.4|^8.0

Since Feb 16Pushed 1y ago1 watchersCompare

[ Source](https://github.com/Mediagone/symfony-easy-api)[ Packagist](https://packagist.org/packages/mediagone/symfony-easy-api)[ RSS](/packages/mediagone-symfony-easy-api/feed)WikiDiscussions main Synced 1mo ago

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

Symfony EasyAPI
===============

[](#symfony-easyapi)

[![Latest Version on Packagist](https://camo.githubusercontent.com/79a4f6e12ad110d02c98fefb7cfe0b06c45ae27087d6041cde07503cfc8d1e3a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d65646961676f6e652f73796d666f6e792d656173792d6170692e737667)](https://packagist.org/packages/mediagone/symfony-easy-api)[![Total Downloads](https://camo.githubusercontent.com/fde3005b2ad4e36937c98a25a6446c6d1a62790b7e69098f259b893b24309b36/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d65646961676f6e652f73796d666f6e792d656173792d6170692e737667)](https://packagist.org/packages/mediagone/symfony-easy-api)[![Software License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)

This package provides helper classes to build a Json API very easily from plain *Symfony* controllers.
Supported features :

- Single and Collection results
- Pagination for Collection results
- Out of the box support for most useful status codes (200, 201, 202, 204, 400, 401, 403, 404, 405, 409, 410, 415, 422, 429, 500 and 501).

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

[](#installation)

This package requires **PHP 7.4+**.

Add it as Composer dependency:

```
$ composer require mediagone/symfony-easy-api
```

Introduction
------------

[](#introduction)

This package provides several classes to handle API requests and return structured JSON responses:

- `ApiPayload200Success`
- `ApiPayload201Created`
- `ApiPayload202Accepted`
- `ApiPayload204NoContent`
- `ApiPayloadError400BadRequest`
- `ApiPayloadError401Unauthorized`
- `ApiPayloadError403Forbidden`
- `ApiPayloadError404NotFound`
- `ApiPayloadError405MethodNotAllowed`
- `ApiPayloadError409Conflict`
- `ApiPayloadError410Gone`
- `ApiPayloadError415UnsupportedMediaType`
- `ApiPayloadError422UnprocessableEntity`
- `ApiPayloadError429TooManyRequests`
- `ApiPayloadError500ServerError`
- `ApiPayloadError501NotImplemented`

Examples
--------

[](#examples)

The easiest way to build an API controller is to use the `EasyApi` class and wrap the controller code in an anonymous function, to benefit from automatic error handling.

### 1. Entity instance API endpoint

[](#1-entity-instance-api-endpoint)

The `EasyApi->response` method accepts any callable argument that returns an `ApiPayload` instance.

```
use App\Thing\ThingRepository;
use Mediagone\Symfony\EasyApi\EasyApi;
use Mediagone\Symfony\EasyApi\Payloads\ApiPayload200Success;
use Mediagone\Symfony\EasyApi\Payloads\ApiPayloadError404NotFound;
use Symfony\Component\HttpFoundation\Response;

/**
 * @Route("/api/things/{thingId}", name="api_things", methods={"GET"})
 */
final class ApiEndpointController
{

    public function __invoke(int $thingId, EasyApi $easyApi, ThingRepository $thingRepository) : Response
    {
        return $easyApi->response(
            function() use ($thingId, $thingRepository) {
                // Any uncatched exception would be automatically converted into an ApiPayloadError500ServerError response's payload.
                if ($thingId < 1) {
                    throw new LogicException("Invalid `\$thingId` value ($thingId)");
                }

                $thing = $thingRepository->find($thingId);
                if ($thing === null) {
                    // Explicit "not found" error response's payload
                    return ApiPayloadError404NotFound::create('Thing not found (id: '.$thingId.')');
                }

                return ApiPayload200Success::createWithSingleResult($thing);
            }
        );
    }

}
```

In case of success, the previous controller will return the following JSON object:

```
{
    "success": true,
    "status": "ok",
    "statusCode": 200,
    "payload": {
        "result": {
            "id": 1,
            "name": "First thing"
        }
    }
}
```

Or a "not found" response:

```
{
    "success": false,
    "status": "not_found",
    "statusCode": 404,
    "error": "not_found",
    "errorDescription": "Thing not found (id: 1)",
    "errorCode": 0
}
```

Or a "server error" response:

```
{
    "success": false,
    "status": "server_error",
    "statusCode": 500,
    "error": "server_error",
    "errorDescription": "Unexpected server error: Invalid `$thingId` value (-1)",
    "errorCode": 0
}
```

*Note: `errorCode` is the internal error's code of the PHP exception (0 by default). You can generally define it by passing an additional integer argument to the constructor, eg. `throw new LogicException("Invalid `$thingId` value ($thingId)", 1234);`.*

### 2. Entity collection API endpoint

[](#2-entity-collection-api-endpoint)

You can also return multiple results by using the `ApiPayload200Success::createWithArrayResult` factory method:

```
/**
 * @Route("/api/things", name="api_things", methods={"GET"})
 */
final class ApiEndpointController
{

    public function __invoke(EasyApi $easyApi, ThingRepository $thingRepository) : Response
    {
        return $easyApi->response(
            function() use ($thingRepository)
            {
                $things = $thingRepository->findAll();
                return ApiPayload200Success::createWithArrayResult($things);
            }
        );
    }

}
```

It will result in a slightly different JSON object:

```
{
    "success": true,
    "status": "ok",
    "statusCode": 200,
    "payload": {
        "results": [
            { "id": 1, "name": "First thing" },
            { "id": 2, "name": "Second thing" },
            { "id": 3, "name": "Third thing" }
        ],
        "resultsCount": 3,
        "resultsCountTotal": 3,
        "page": 1,
        "pageCount": 1
    }
}
```

### 3. Collection pagination

[](#3-collection-pagination)

When dealing with a lot of database entries, you may want to paginate results to retrieve them chunk by chunk.
The package provides the `ApiPagination` class to help with that feature.

It requires two database queries: one to count the total number of results, and another to fetch the requested results:

```
use Mediagone\Symfony\EasyApi\EasyApi;
use Mediagone\Symfony\EasyApi\Payloads\ApiPayload;
use Mediagone\Symfony\EasyApi\Payloads\ApiPayload200Success;
use Mediagone\Symfony\EasyApi\Request\ApiPagination;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

#[Route('/api/things/{requestedPage}', name:'api_things_list')]
public function __invoke(int $requestedPage = 1, ThingRepository $thingRepository): Response
{
    return $easyApi->response(static function () use ($requestedPage, $thingRepository) : ApiPayload {
        // Count the total number of Things in the db
        $thingsCount = $thingRepository->countAll();

        // Create a pagination object
        $pagination = ApiPagination::create($requestedPage, 5, $thingsCount);

        // Query the page's results
        $things = $thingRepository->findAllPaginated($pagination);

        return ApiPayload200Success::createWithArrayResult($things, $pagination);
    }
}
```

Assuming that you have 93 rows in your database and you are requesting the 2nd page of 5 results, you'll receive the following JSON response:

```
{
    "success": true,
    "status": "ok",
    "statusCode": 200,
    "payload": {
        "results": [
            { "id": 6, "name": "6th thing" },
            { "id": 7, "name": "7th thing" },
            { "id": 8, "name": "8th thing" },
            { "id": 9, "name": "9th thing" },
            { "id": 10, "name": "10th thing" }
        ],
        "resultsCount": 5,
        "resultsCountTotal": 93,
        "page": 2,
        "pageCount": 19
    }
}
```

License
-------

[](#license)

*Symfony EasyAPI* is licensed under MIT license. See LICENSE file.

###  Health Score

37

—

LowBetter than 82% of packages

Maintenance38

Infrequent updates — may be unmaintained

Popularity21

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 97.7% 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.

###  Release Activity

Cadence

Every ~101 days

Recently: every ~245 days

Total

14

Last Release

591d ago

Major Versions

0.4.0 → 1.0.02024-09-25

### Community

Maintainers

![](https://www.gravatar.com/avatar/ce000f43f69a7dc38a80da57d86a712a3e27f86b5fd4090f024472a03b28a089?d=identicon)[Mediagone](/maintainers/Mediagone)

---

Top Contributors

[![Mediagone](https://avatars.githubusercontent.com/u/32240357?v=4)](https://github.com/Mediagone "Mediagone (43 commits)")[![romm](https://avatars.githubusercontent.com/u/6342901?v=4)](https://github.com/romm "romm (1 commits)")

---

Tags

apijson-apisymfonyjsonapisymfony

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mediagone-symfony-easy-api/health.svg)

```
[![Health](https://phpackages.com/badges/mediagone-symfony-easy-api/health.svg)](https://phpackages.com/packages/mediagone-symfony-easy-api)
```

###  Alternatives

[nilportugues/jsonapi-bundle

Symfony 2 &amp; 3 JSON API Transformer Package

11446.0k](/packages/nilportugues-jsonapi-bundle)[mtarld/api-platform-ms-bundle

API Platform Microservice Bundle

7124.5k](/packages/mtarld-api-platform-ms-bundle)[dragon-code/laravel-json-response

Automatically always return a response in JSON format

1118.6k1](/packages/dragon-code-laravel-json-response)[uderline/openapi-php-attributes

Automatically render your OpenApi 3 file describing your PHP API using attributes

2136.3k](/packages/uderline-openapi-php-attributes)[stfalcon-studio/api-bundle

Base classes and helper services to build API application via Symfony.

1032.1k](/packages/stfalcon-studio-api-bundle)

PHPackages © 2026

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