PHPackages                             cesurapp/api-bundle - 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. cesurapp/api-bundle

ActiveSymfony-bundle[API Development](/categories/api)

cesurapp/api-bundle
===================

Symfony Api Bundle

2.2.9(2mo ago)0362MITPHPPHP &gt;=8.4CI passing

Since Dec 15Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/cesurapp/api-bundle)[ Packagist](https://packagist.org/packages/cesurapp/api-bundle)[ Docs](https://github.com/cesurapp/api-bundle)[ RSS](/packages/cesurapp-api-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (17)Versions (40)Used By (0)

Symfony Api Bundle
==================

[](#symfony-api-bundle)

[![App Tester](https://github.com/cesurapp/api-bundle/actions/workflows/testing.yaml/badge.svg)](https://github.com/cesurapp/api-bundle/actions/workflows/testing.yaml)[![Software License](https://camo.githubusercontent.com/e99b24ac55a940bfbc522043865b6e8934548d8524587e0d1540d163ca9e85b3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f6c6f676f3d556e6c6963656e7365)](LICENSE.md)

This package allows you to expose fast API endpoints with Symfony.

**Features:**

- JSON request body transformer
- Error messages collected under a single format
- Language translation applied to all error messages
- Custom CORS header support
- Automatic documentation generator (Thor)
- TypeScript client generator
- API DTO resolver with auto-validation
- Doctrine filter &amp; sorter resource
- PhoneNumber, UniqueEntity, Username validators
- Excel, CSV exporter (Sonata Export Bundle)

**Documentation:**

- [GUIDELINES.md](GUIDELINES.md) - Comprehensive usage guide for developers and AI agents

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

[](#installation)

**Requirements:** Symfony 8+, PHP 8.1+

```
composer require cesurapp/api-bundle
```

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

[](#configuration)

Create `config/packages/api.yaml`:

```
api:
  exception_converter: false
  cors_header:
    - { name: 'Access-Control-Allow-Origin', value: '*' }
    - { name: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,PATCH,DELETE' }
    - { name: 'Access-Control-Allow-Headers', value: '*' }
    - { name: 'Access-Control-Expose-Headers', value: 'Content-Disposition' }
  thor:
    base_url: "%env(APP_DEFAULT_URI)%"
    global_config:
      authHeader:
        Content-Type: application/authheader
        Authorization: 'Bearer Token'
      query: []
      request: []
      header:
        Content-Type: application/header
        Accept: application/headaadsa
      response: []
      isAuth: true
      isPaginate: true
      isHidden: false
```

TypeScript Client Generation
----------------------------

[](#typescript-client-generation)

**View Documentation:**

```
bin/console thor:extract ./output-directory
```

Usage Examples
--------------

[](#usage-examples)

### Basic Controller with POST Endpoint

[](#basic-controller-with-post-endpoint)

```
use Cesurapp\ApiBundle\AbstractClass\ApiController;
use Cesurapp\ApiBundle\Response\ApiResponse;
use Cesurapp\ApiBundle\Thor\Attribute\Thor;
use Symfony\Component\Routing\Annotation\Route;

class UserController extends ApiController
{
    #[Thor(
        stack: 'User|1',
        title: 'Create User',
        info: 'Creates a new user account',
        request: [
            'email' => 'string',
            'password' => 'string',
            'name' => 'string',
        ],
        response: [
            200 => ['data' => UserResource::class],
        ],
        dto: CreateUserDto::class,
        isAuth: false,
        isPaginate: false
    )]
    #[Route('/users', methods: ['POST'])]
    public function create(CreateUserDto $dto): ApiResponse
    {
        $user = new User();
        $user->setEmail($dto->email);
        $user->setPassword($dto->password);
        $user->setName($dto->name);

        $this->entityManager->persist($user);
        $this->entityManager->flush();

        return ApiResponse::create()
            ->setData($user)
            ->setResource(UserResource::class);
    }

    #[Thor(
        stack: 'User|2',
        title: 'List Users',
        query: [
            'filter' => [
                'name' => '?string',
                'email' => '?string',
            ],
        ],
        response: [200 => ['data' => UserResource::class]],
        isAuth: true,
        isPaginate: true
    )]
    #[Route('/users', methods: ['GET'])]
    public function list(UserRepository $repo): ApiResponse
    {
        return ApiResponse::create()
            ->setQuery($repo->createQueryBuilder('u'))
            ->setPaginate()
            ->setResource(UserResource::class);
    }
}
```

### API Resource

[](#api-resource)

**Purpose:** Transform entities to API responses and define filtering/sorting behavior.

**Note:** Filters and DataTable features only work when pagination is enabled.

```
use Cesurapp\ApiBundle\Response\ApiResourceInterface;
use Doctrine\ORM\QueryBuilder;

class UserResource implements ApiResourceInterface
{
    public function toArray(mixed $item, mixed $optional = null): array
    {
        return [
            'id' => $item->getId(),
            'email' => $item->getEmail(),
            'name' => $item->getName(),
            'createdAt' => $item->getCreatedAt()->format(\DateTime::ATOM),
        ];
    }

    public function toResource(): array
    {
        return [
            'id' => [
                'type' => 'string',
                'filter' => static function (QueryBuilder $builder, string $alias, mixed $data) {
                    $builder->andWhere("$alias.id = :id")->setParameter('id', $data);
                },
                'table' => [
                    'label' => 'ID',
                    'sortable' => true,
                    'sortable_default' => true,
                    'sortable_desc' => true,
                    'filter_input' => 'input',
                ],
            ],
            'email' => [
                'type' => 'string',
                'filter' => static function (QueryBuilder $builder, string $alias, mixed $data) {
                    $builder->andWhere("$alias.email LIKE :email")
                        ->setParameter('email', "%$data%");
                },
                'table' => [
                    'label' => 'Email',
                    'sortable' => true,
                    'filter_input' => 'input',
                ],
            ],
            'createdAt' => [
                'type' => 'string',
                'filter' => [
                    'from' => static function (QueryBuilder $builder, string $alias, mixed $data) {
                        $builder->andWhere("$alias.createdAt >= :dateFrom")
                            ->setParameter('dateFrom', $data);
                    },
                    'to' => static function (QueryBuilder $builder, string $alias, mixed $data) {
                        $builder->andWhere("$alias.createdAt
