cesurapp / api-bundle
Symfony Api Bundle
2.0.11
2024-09-19 21:28 UTC
Requires
- php: >=8.2
- doctrine/doctrine-bundle: ^2.10
- doctrine/orm: ^2.15
- giggsey/libphonenumber-for-php-lite: ^8.13
- sonata-project/exporter: ^3.3
- symfony/dependency-injection: ^7.0
- symfony/filesystem: ^7.0
- symfony/framework-bundle: ^7.0
- symfony/http-kernel: ^7.0
- symfony/intl: ^7.0
- symfony/mime: ^7.0
- symfony/security-bundle: ^7.0
- symfony/translation: ^7.0
- symfony/validator: ^7.0
Requires (Dev)
- php-cs-fixer/shim: ^3.40
- phpstan/phpstan: ^1.10
- symfony/test-pack: ^1.1
README
此软件包允许您使用Symfony公开快速API端点。
功能
- Json请求体转换器
- 错误消息收集在单一格式下。
- 对所有错误消息应用语言翻译。
- 自定义CORS头部支持
- 自动文档生成器(Thor)
- TypeScript客户端生成器
- Api DTO解析器
- Doctrine筛选器 & 排序资源
- PhoneNumber, UniqueEntity, Username验证器
- Excel, Csv导出器(Sonata Export Bundle)
安装
需要Symfony 7
composer req cesurapp/api-bundle
配置: 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客户端
查看文档: http:://127.0.0.1:8000/thor
bin/console thor:extract ./path # Generate Documentation to Directory
创建API响应
use \Cesurapp\ApiBundle\AbstractClass\ApiController; use \Cesurapp\ApiBundle\Response\ApiResponse; use \Cesurapp\ApiBundle\Thor\Attribute\Thor; use \Symfony\Component\Routing\Annotation\Route; class TestController extends ApiController { #[Thor( stack: 'Login|1', title: 'Login EndPoint', info: "Description", request: [ 'username' => 'string', 'password' => 'string', ], response: [ 200 => ['data' => UserResource::class], BadCredentialsException::class, TokenExpiredException::class, AccessDeniedException::class ], dto: LoginDto::class, isAuth: false, isPaginate: false, order: 0 )] #[Route(name: 'Login', path: '/login', methods: ['POST'])] public function getMethod(LoginDto $loginDto): ApiResponse { return ApiResponse::create() ->setData(['custom-data']) ->setQuery('QueryBuilder') ->setHTTPCache(60) // Enable HTTP Cache ->setPaginate() // Enable QueryBuilder Paginator ->setHeaders([]) // Custom Header ->setResource(UserResource::class) } #[Thor( stack: 'Profile|2', title: 'Profile EndPoint', query: [ 'name' => '?string', 'filter' => [ 'id' => '?int', 'name' => '?string', 'fullName' => '?string', ], ], response: [200 => ['data' => UserResource::class]], isAuth: true, isPaginate: false, order: 0 )] #[Route(name: 'GetExample', path: '/get', methods: ['GET'])] public function postMethod(): ApiResponse { $query = $userRepo->createQueryBuilder('q'); return ApiResponse::create() ->setQuery($query) ->setPaginate() // Enable QueryBuilder Paginator ->setHeaders([]) // Custom Header ->setResource(UserResource::class) } }
创建API资源
筛选和DataTable仅在启用分页时工作。自动创建TS列用于表格。所有表格的导出都自动启用。
use \Cesurapp\ApiBundle\Response\ApiResourceInterface; class UserResource implements ApiResourceInterface { public function toArray(mixed $item, mixed $optional = null): array { return [ 'id' => $object->getId(), 'name' => $object->getName() ] } public function toResource(): array { return [ 'id' => [ 'type' => 'string', // Typescript Type -> ?string|?int|?boolean|?array|?object|NotificationResource::class| 'filter' => static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[id]=test 'table' => [ // Typescript DataTable Types 'label' => 'ID', // DataTable Label 'sortable' => true, // DataTable Sortable Column 'sortable_default' => true, // DataTable Default Sortable Column 'sortable_desc' => true, // DataTable Sortable DESC 'filter_input' => 'input', // DataTable Add Filter Input Type -> input|number|date|daterange|checkbox|country|language // These fields are used in the backend. It doesn't transfer to the frontend. 'exporter' => static fn($v) => $v, // Export Column Template 'sortable_field' => 'firstName', // Doctrine Getter Method 'sortable_field' => static fn (QueryBuilder $builder, string $direction) => $builder->orderBy('u.firstName', $direction), ], ], 'created_at' => [ 'type' => 'string', 'filter' => [ 'from' => static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[created_at][min]=test 'to' => static function (QueryBuilder $builder, string $alias, mixed $data) {}, // app.test?filter[created_at][max]=test ] ] ] } }
使用筛选
筛选器根据查询参数设置。仅过滤匹配的记录。
示例请求 http://example.test/v1/userlist?filter[id]=1&filter[createdAt][min]=10.10.2023
创建表单验证
后端日期以UTC ATOM格式存储。在GET请求中,您将收到ATOM格式的日期。在POST|PUT请求中,发送ATOM格式的日期,转换为UTC。
use Cesurapp\ApiBundle\AbstractClass\ApiDto; use Cesurapp\ApiBundle\Thor\Attribute\ThorResource; use Symfony\Component\Validator\Constraints as Assert; class LoginDto extends ApiDto { /** * Enable Auto Validation -> Default Enabled */ protected bool $auto = true; /** * Form Fields */ #[Assert\NotNull] public string|int|null|bool $name; #[Assert\Length(min: 3, max: 100)] public ?string $lastName; #[Assert\Length(min: 10, max: 100)] #[Assert\NotNull] public int $phone; #[Assert\NotNull] #[Assert\GreaterThan(new \DateTimeImmutable())] public \DateTimeImmutable $send_at; #[Assert\Optional([ new Assert\Type('array'), new Assert\Count(['min' => 1]), new Assert\All([ new Assert\Collection([ 'slug' => [ new Assert\NotBlank(), new Assert\Type(['type' => 'string']), ], 'label' => [ new Assert\NotBlank(), ], ]), ]), ])] #[ThorResource(data: [[ 'slug' => 'string', 'label' => 'string|int|boolean', ]])] public ?array $data; }