{"id":15077677,"url":"https://github.com/cesurapp/api-bundle","last_synced_at":"2026-01-19T08:00:48.718Z","repository":{"id":210730750,"uuid":"726645802","full_name":"cesurapp/api-bundle","owner":"cesurapp","description":"Symfony API Bundle","archived":false,"fork":false,"pushed_at":"2026-01-17T09:22:20.000Z","size":234,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-17T20:37:24.290Z","etag":null,"topics":["api","json-api","rest-api","symfony","symfony-bundle"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cesurapp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"fabpot","tidelift":"packagist/symfony/symfony","custom":"https://symfony.com/sponsor"}},"created_at":"2023-12-03T00:13:56.000Z","updated_at":"2026-01-17T09:21:47.000Z","dependencies_parsed_at":"2024-01-01T05:25:11.959Z","dependency_job_id":"cd1f1812-1dfa-4c25-a5a6-265431414ffa","html_url":"https://github.com/cesurapp/api-bundle","commit_stats":{"total_commits":49,"total_committers":1,"mean_commits":49.0,"dds":0.0,"last_synced_commit":"e32ed9d1615229d29215cae909bc86e8b7fd9f2d"},"previous_names":["cesurapp/api-bundle"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/cesurapp/api-bundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesurapp%2Fapi-bundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesurapp%2Fapi-bundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesurapp%2Fapi-bundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesurapp%2Fapi-bundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cesurapp","download_url":"https://codeload.github.com/cesurapp/api-bundle/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cesurapp%2Fapi-bundle/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28563200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T03:31:16.861Z","status":"ssl_error","status_checked_at":"2026-01-19T03:31:15.069Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","json-api","rest-api","symfony","symfony-bundle"],"created_at":"2024-09-25T04:06:45.158Z","updated_at":"2026-01-19T08:00:48.705Z","avatar_url":"https://github.com/cesurapp.png","language":"PHP","readme":"# Symfony Api Bundle\n\n[![App Tester](https://github.com/cesurapp/api-bundle/actions/workflows/testing.yaml/badge.svg)](https://github.com/cesurapp/api-bundle/actions/workflows/testing.yaml)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?logo=Unlicense)](LICENSE.md)\n\nThis package allows you to expose fast api endpoints with Symfony. \n\n__Features:__\n* Json request body transformer \n* Error messages are collected under a single format.\n* Language translation is applied to all error messages.\n* Custom cors header support\n* Automatic documentation generator (Thor)\n* Typescript client generator\n* Api DTO resolver\n* Doctrine filter \u0026 sorter resource\n* PhoneNumber, UniqueEntity, Username validator\n* Excel, Csv exporter (Sonata Export Bundle)\n\n### Install\nRequired Symfony 8\n```shell\ncomposer req cesurapp/api-bundle\n```\n\n__Configuration:__ config/packages/api.yaml\n```yaml\napi:\n  exception_converter: false\n  cors_header:\n    - { name: 'Access-Control-Allow-Origin', value: '*' }\n    - { name: 'Access-Control-Allow-Methods', value: 'GET,POST,PUT,PATCH,DELETE' }\n    - { name: 'Access-Control-Allow-Headers', value: '*' }\n    - { name: 'Access-Control-Expose-Headers', value: 'Content-Disposition' }\n  thor:\n    base_url: \"%env(APP_DEFAULT_URI)%\"\n    global_config:\n      authHeader:\n        Content-Type: application/authheader\n        Authorization: 'Bearer Token'\n      query: []\n      request: []\n      header:\n        Content-Type: application/header\n        Accept: application/headaadsa\n      response: []\n      isAuth: true\n      isPaginate: true\n      isHidden: false\n```\n\n### Generate TypeScript Client\n__View Documentation:__ http:://127.0.0.1:8000/thor\n```shell\nbin/console thor:extract ./path # Generate Documentation to Directory\n```\n\n### Create Api Response\n\n```php\nuse \\Cesurapp\\ApiBundle\\AbstractClass\\ApiController;\nuse \\Cesurapp\\ApiBundle\\Response\\ApiResponse;\nuse \\Cesurapp\\ApiBundle\\Thor\\Attribute\\Thor;\nuse \\Symfony\\Component\\Routing\\Annotation\\Route;\n\nclass TestController extends ApiController {\n    #[Thor(\n        stack: 'Login|1',\n        title: 'Login EndPoint',\n        info: \"Description\",\n        request: [\n            'username' =\u003e 'string',\n            'password' =\u003e 'string',\n        ],\n        response: [\n            200 =\u003e ['data' =\u003e UserResource::class],\n            BadCredentialsException::class,\n            TokenExpiredException::class,\n            AccessDeniedException::class\n        ],\n        dto: LoginDto::class, \n        isAuth: false, \n        isPaginate: false, \n        order: 0\n    )]\n    #[Route(name: 'Login', path: '/login', methods: ['POST'])]\n    public function getMethod(LoginDto $loginDto): ApiResponse {\n        return ApiResponse::create()\n            -\u003esetData(['custom-data'])\n            -\u003esetQuery('QueryBuilder')\n            -\u003esetHTTPCache(60)  // Enable HTTP Cache\n            -\u003esetPaginate()     // Enable QueryBuilder Paginator\n            -\u003esetHeaders([])    // Custom Header\n            -\u003esetResource(UserResource::class)\n    }\n    \n    #[Thor(\n        stack: 'Profile|2',\n        title: 'Profile EndPoint',\n        query: [\n            'name' =\u003e '?string',\n            'filter' =\u003e [\n                'id' =\u003e '?int',\n                'name' =\u003e '?string',\n                'fullName' =\u003e '?string',\n            ],\n        ],\n        response: [200 =\u003e ['data' =\u003e UserResource::class]],\n        isAuth: true, \n        isPaginate: false, \n        order: 0\n    )]\n    #[Route(name: 'GetExample', path: '/get', methods: ['GET'])]\n    public function postMethod(): ApiResponse {\n        $query = $userRepo-\u003ecreateQueryBuilder('q');\n        \n        return ApiResponse::create()\n            -\u003esetQuery($query)\n            -\u003esetPaginate()     // Enable QueryBuilder Paginator\n            -\u003esetHeaders([])    // Custom Header\n            -\u003esetResource(UserResource::class)\n    }\n}\n```\n\n### Create Api Resource\nFilter and DataTable only work when pagination is enabled. Automatic TS columns are created for the table.\nExport is automatically enabled for all tables.\n\n```php\nuse \\Cesurapp\\ApiBundle\\Response\\ApiResourceInterface;\n\nclass UserResource implements ApiResourceInterface {\n    public function toArray(mixed $item, mixed $optional = null): array {\n        return [\n            'id' =\u003e $object-\u003egetId(),\n            'name' =\u003e $object-\u003egetName()\n        ]\n    }\n    \n    public function toResource(): array {\n        return [\n              'id' =\u003e [\n                'type' =\u003e 'string', // Typescript Type -\u003e ?string|?int|?boolean|?array|?object|NotificationResource::class|\n                'filter' =\u003e static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[id]=test\n                'table' =\u003e [ // Typescript DataTable Types\n                    'label' =\u003e 'ID',                     // DataTable Label\n                    'sortable' =\u003e true,                  // DataTable Sortable Column   \n                    'sortable_default' =\u003e true,          // DataTable Default Sortable Column\n                    'sortable_desc' =\u003e true,             // DataTable Sortable DESC\n                    'filter_input' =\u003e 'input',           // DataTable Add Filter Input Type -\u003e input|number|date|daterange|checkbox|country|language\n                   \n                    // These fields are used in the backend. It doesn't transfer to the frontend. \n                    'exporter' =\u003e static fn($v) =\u003e $v,   // Export Column Template\n                    'sortable_field' =\u003e 'firstName',     // Doctrine Getter Method\n                    'sortable_field' =\u003e static fn (QueryBuilder $builder, string $direction) =\u003e $builder-\u003eorderBy('u.firstName', $direction),\n                ],\n            ],\n            'created_at' =\u003e [\n                'type' =\u003e 'string',\n                'filter' =\u003e [\n                    'from' =\u003e static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[created_at][min]=test\n                    'to' =\u003e static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[created_at][max]=test\n                ]\n            ]\n        ]   \n    }\n\n}\n```\n\n__Using Filter__\n\nFilters are set according to the query parameter. Only matching records are filtered.\n\nSample request `http://example.test/v1/userlist?filter[id]=1\u0026filter[createdAt][min]=10.10.2023`\n\n### Create Form Validation\nBackend dates are stored in UTC ATOM format. In GET requests you get dates in ATOM format.\nIn POST|PUT requests, send dates in ATOM format, converted to UTC.\n\n```php\nuse Cesurapp\\ApiBundle\\AbstractClass\\ApiDto;\nuse Cesurapp\\ApiBundle\\Thor\\Attribute\\ThorResource;\nuse Symfony\\Component\\Validator\\Constraints as Assert;\n\nclass LoginDto extends ApiDto {\n    /**\n     * Enable Auto Validation -\u003e Default Enabled\n     */\n    protected bool $auto = true;\n    \n    /**\n     * Form Fields\n     */\n    #[Assert\\NotNull]\n    public string|int|null|bool $name;\n\n    #[Assert\\Length(min: 3, max: 100)]\n    public ?string $lastName;\n\n    #[Assert\\Length(min: 10, max: 100)]\n    #[Assert\\NotNull]\n    public int $phone;\n\n    #[Assert\\NotNull]\n    #[Assert\\GreaterThan(new \\DateTimeImmutable())]\n    public \\DateTimeImmutable $send_at;\n    \n    #[Assert\\Optional([\n        new Assert\\Type('array'),\n        new Assert\\Count(['min' =\u003e 1]),\n        new Assert\\All([\n            new Assert\\Collection([\n                'slug' =\u003e [\n                    new Assert\\NotBlank(),\n                    new Assert\\Type(['type' =\u003e 'string']),\n                ],\n                'label' =\u003e [\n                    new Assert\\NotBlank(),\n                ],\n            ]),\n        ]),\n    ])]\n    #[ThorResource(data: [[\n        'slug' =\u003e 'string',\n        'label' =\u003e 'string|int|boolean',\n    ]])]\n    public ?array $data;\n}\n```","funding_links":["https://github.com/sponsors/fabpot","https://tidelift.com/funding/github/packagist/symfony/symfony","https://symfony.com/sponsor"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesurapp%2Fapi-bundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcesurapp%2Fapi-bundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcesurapp%2Fapi-bundle/lists"}