Skill api-filter
Añade filtros a las colecciones de API Platform utilizando el enfoque canónico de QueryParameter para búsquedas, ordenamiento y filtrado por rangos.
- Estrellas en GitHub
- 29
- Archivos
- 1
- Último commit
- 22 oct 2026
- Licencia
- —
- Herramientas permitidas
- —
¿Qué hace la skill api-filter?
api-filter es una agent skill. Añade filtros a las colecciones de API Platform utilizando el enfoque canónico de QueryParameter para búsquedas, ordenamiento y filtrado por rangos.
Resumen generado a partir del SKILL.md de la skill.
Sobre la skill api-filter
Este SKILL permite a los desarrolladores backend implementar búsquedas, ordenamiento y filtrado por rangos en las colecciones de API Platform. Proporciona una forma de declarar filtros mediante el enfoque QueryParameter dentro del array de parámetros de una operación, que es el método requerido para API Platform 4.4 y versiones posteriores. Este enfoque es explícito por operación y funciona con cualquier state provider, lo que lo convierte en una forma fiable de gestionar las peticiones del cliente para subconjuntos de datos específicos.
Los desarrolladores pueden usar esto para reemplazar atributos obsoletos a nivel de clase como #[ApiFilter] o filtros específicos como SearchFilter, BooleanFilter y OrderFilter. El SKILL es compatible tanto con Doctrine ORM como con MongoDB ODM a través de un conjunto de filtros de propósito único que incluyen ExactFilter, PartialSearchFilter, DateFilter y SortFilter. También gestiona necesidades especializadas como búsquedas por IRI con IriFilter o la difusión de un único valor en múltiples campos mediante FreeTextQueryFilter. Para quienes utilizan Laravel, ofrece orientación sobre el uso del conjunto de filtros específico de Eloquent y las reglas de validación de Laravel.
Lo que un agente puede hacer con ella
- 1Migrar filtros de API heredadosConvierte los atributos #[ApiFilter] obsoletos a nivel de clase al enfoque moderno de QueryParameter.
- 2Añadir búsqueda de texto libre en múltiples camposCrea un único parámetro de búsqueda que verifique un valor en varias propiedades distintas.
- 3Configurar filtros de Laravel EloquentConfigura el filtrado para modelos de Laravel utilizando las clases de filtro de Eloquent y las reglas de validación específicas.
Escrito a partir del SKILL.md de la skill. Cada caso de uso se verifica con una cita del mismo.
Cómo instalar la skill api-filter
Cada comando copia la carpeta de la skill al directorio de skills del cliente. Reinicia el cliente o inicia una nueva sesión para cargarla.Instalar la skill api-filter en Plugin
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Instalar la skill api-filter en Claude Code
~/.claude/skills/api-filter/SKILL.md
$ npx degit api-platform/skillset/skills/api-filter ~/.claude/skills/api-filterInstalar la skill api-filter en Claude Code (project)
.claude/skills/api-filter/SKILL.md
$ npx degit api-platform/skillset/skills/api-filter .claude/skills/api-filterInstalar la skill api-filter en Codex
~/.agents/skills/api-filter/SKILL.md
$ npx degit api-platform/skillset/skills/api-filter ~/.agents/skills/api-filterInstalar la skill api-filter en Gemini CLI
~/.gemini/skills/api-filter/SKILL.md
$ npx degit api-platform/skillset/skills/api-filter ~/.gemini/skills/api-filterInstalar la skill api-filter en Claude.ai
npx degit api-platform/skillset/skills/api-filter api-filter && zip -r api-filter.zip api-filter # claude.ai → Customize → Skills → + → Create skill → Upload a skill → api-filter.zip
SKILL.md
Ver en GitHubAdding Filters to Collections
Declare filters with QueryParameter in the operation's parameters: array. The
key is the query-string parameter exposed to clients; the filter: is the filter
instance. This is the canonical approach for API Platform 4.4+ — it works with any
state provider and is per-operation explicit.
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\QueryParameter;
use ApiPlatform\Doctrine\Orm\Filter\ExactFilter;
#[GetCollection(
parameters: [
'status' => new QueryParameter(filter: new ExactFilter()),
],
)]
class Order {}
Client: GET /orders?status=shipped
#[ApiFilter]is legacy. The class-level#[ApiFilter(SearchFilter::class, ...)]attribute and the multi-strategy filters (SearchFilter,BooleanFilter,NumericFilter,OrderFilter,BackedEnumFilter) are deprecated in 4.4 and removed in 6.0. Don't teach or add them in new code. If you encounter them, the migration target is theQueryParameter+ single-purpose filter set below. The mapping is in the table at the bottom.
Canonical filter set
Each filter does one thing. They live in two parallel namespaces — pick the one matching your persistence layer:
| Filter | Purpose | ORM | MongoDB ODM |
|---|---|---|---|
ExactFilter |
equality, multi-value (IN); booleans/ints/enums via nativeType |
ApiPlatform\Doctrine\Orm\Filter\ExactFilter |
ApiPlatform\Doctrine\Odm\Filter\ExactFilter |
PartialSearchFilter |
LIKE %x% substring |
…\Orm\Filter\PartialSearchFilter |
…\Odm\Filter\PartialSearchFilter |
ComparisonFilter |
gt/gte/lt/lte/ne (decorates an equality filter) |
…\Orm\Filter\ComparisonFilter |
…\Odm\Filter\ComparisonFilter |
SortFilter |
ORDER BY |
…\Orm\Filter\SortFilter |
…\Odm\Filter\SortFilter |
DateFilter |
before/after date ranges |
…\Orm\Filter\DateFilter |
…\Odm\Filter\DateFilter |
RangeFilter |
between/gt/lt on numbers |
…\Orm\Filter\RangeFilter |
…\Odm\Filter\RangeFilter |
ExistsFilter |
IS NULL / IS NOT NULL |
…\Orm\Filter\ExistsFilter |
…\Odm\Filter\ExistsFilter |
IriFilter |
relationship lookup by IRI | …\Orm\Filter\IriFilter |
…\Odm\Filter\IriFilter |
OrFilter |
decorator: switches a primary's WHERE to orWhere |
…\Orm\Filter\OrFilter |
…\Odm\Filter\OrFilter |
FreeTextQueryFilter |
decorator: broadcasts one value across N properties | …\Orm\Filter\FreeTextQueryFilter |
…\Odm\Filter\FreeTextQueryFilter |
ComparisonFilterandOrFilterare still marked@experimentalin 4.4 — they are the intended migration target but their API may shift before stabilizing.
Common filters
Exact match
'status' => new QueryParameter(filter: new ExactFilter())
GET /orders?status=shipped. Arrays produce an IN: ?status[]=draft&status[]=sent.
Boolean / integer / enum — ExactFilter + nativeType
There is no BooleanFilter in the canonical set. Use ExactFilter and declare the
native type so values are cast and documented correctly:
use Symfony\Component\TypeInfo\Type\BuiltinType;
use Symfony\Component\TypeInfo\TypeIdentifier;
'active' => new QueryParameter(
filter: new ExactFilter(),
nativeType: new BuiltinType(TypeIdentifier::BOOL),
),
GET /orders?active=true. Use TypeIdentifier::INT for integers; pass an enum's
native type for backed enums.
Partial search (LIKE)
use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter;
'q' => new QueryParameter(filter: new PartialSearchFilter(), property: 'title')
GET /books?q=harry. property: maps the public param name to the entity field.
Comparison (gt/gte/lt/lte/ne)
use ApiPlatform\Doctrine\Orm\Filter\ComparisonFilter;
'price' => new QueryParameter(filter: new ComparisonFilter(new ExactFilter()))
GET /products?price[gt]=100&price[lte]=500.
Date range
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
'createdAt' => new QueryParameter(filter: new DateFilter())
GET /orders?createdAt[after]=2024-01-01&createdAt[before]=2024-12-31.
Numeric range
use ApiPlatform\Doctrine\Orm\Filter\RangeFilter;
'price' => new QueryParameter(filter: new RangeFilter())
GET /products?price[between]=10..100.
Exists (null check)
use ApiPlatform\Doctrine\Orm\Filter\ExistsFilter;
'deletedAt' => new QueryParameter(filter: new ExistsFilter())
GET /orders?deletedAt[exists]=false.
Relation (IRI)
use ApiPlatform\Doctrine\Orm\Filter\IriFilter;
'author' => new QueryParameter(filter: new IriFilter())
GET /books?author=/authors/1.
Sorting — SortFilter
There is no OrderFilter in the canonical set. Use SortFilter. Two forms:
use ApiPlatform\Doctrine\Orm\Filter\SortFilter;
// Per-property named parameter
'orderName' => new QueryParameter(filter: new SortFilter(), property: 'name'),
// → GET /books?orderName=desc
// Dynamic, OrderFilter-style: one parameter, any allowed property
'order[:property]' => new QueryParameter(filter: new SortFilter()),
// → GET /books?order[name]=asc&order[createdAt]=desc
property: can traverse relations ('department.company.name' sorts across joins).
Control null placement with nullsComparison:
use ApiPlatform\Doctrine\Common\Filter\OrderFilterInterface;
'orderHireDate' => new QueryParameter(
filter: new SortFilter(nullsComparison: OrderFilterInterface::NULLS_ALWAYS_FIRST),
property: 'hireDate',
),
Free-text across multiple fields
FreeTextQueryFilter decorates a primary and broadcasts one value to several
properties; wrap with OrFilter to match any of them:
use ApiPlatform\Doctrine\Orm\Filter\FreeTextQueryFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrFilter;
use ApiPlatform\Doctrine\Orm\Filter\ExactFilter;
'autocomplete' => new QueryParameter(
filter: new FreeTextQueryFilter(new OrFilter(new ExactFilter())),
properties: ['name', 'email', 'description'],
),
GET /users?autocomplete=alice.
Validating filter parameters
use Symfony\Component\Validator\Constraints as Assert;
'length' => new QueryParameter(
filter: new ExactFilter(),
constraints: [new Assert\Length(max: 100)],
)
Invalid values yield a 422 before the query runs.
Default ordering
Set a default sort directly on the operation (no parameter needed):
new GetCollection(order: ['createdAt' => 'DESC'])
Legacy → canonical migration map
| Legacy (deprecated 4.4, removed 6.0) | Canonical replacement |
|---|---|
#[ApiFilter(SearchFilter::class, ['x' => 'exact'])] |
'x' => new QueryParameter(filter: new ExactFilter()) |
SearchFilter strategy partial |
PartialSearchFilter |
BooleanFilter |
ExactFilter + nativeType: BOOL |
NumericFilter |
ExactFilter + nativeType: INT |
BackedEnumFilter |
ExactFilter + enum nativeType |
OrderFilter |
SortFilter |
RangeFilter, DateFilter, ExistsFilter |
same class — survives as drop-in, just move to QueryParameter |
Laravel (Eloquent)
The QueryParameter wiring is identical, but Laravel ships its own Eloquent
filter set under ApiPlatform\Laravel\Eloquent\Filter\ — these are not the Doctrine
classes and the names differ. Declare them with class-level #[QueryParameter] /
#[GetCollection(parameters: …)] on the model (or DTO). The key, property,
properties, :property placeholder and constraints options work the same.
| Need | Doctrine (above) | Laravel Eloquent class |
|---|---|---|
| equality | ExactFilter |
EqualsFilter |
LIKE %x% |
PartialSearchFilter |
PartialSearchFilter |
LIKE x% / %x |
StartSearchFilter / EndSearchFilter |
StartSearchFilter / EndSearchFilter |
| boolean | ExactFilter + nativeType |
BooleanFilter |
| date range | DateFilter |
DateFilter (filterContext: ['include_nulls' => true] to keep nulls; default excludes) |
| numeric range | RangeFilter |
RangeFilter |
| sort | SortFilter |
OrderFilter |
| OR | OrFilter |
OrFilter (decorator: new OrFilter(new EqualsFilter())) |
use ApiPlatform\Laravel\Eloquent\Filter\EqualsFilter;
use ApiPlatform\Laravel\Eloquent\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\QueryParameter;
#[ApiResource]
#[QueryParameter(key: 'name', filter: EqualsFilter::class)]
#[QueryParameter(key: 'sort[:property]', filter: OrderFilter::class, properties: ['name', 'id'])]
class Book extends Model {}
Constraints are Laravel validation rules (a string/array), not Symfony
constraints: new QueryParameter(key: 'name', filter: PartialSearchFilter::class, constraints: 'min:2').
Custom filters implement ApiPlatform\Laravel\Eloquent\Filter\FilterInterface
(apply(Builder $builder, mixed $values, Parameter $parameter, array $context = []): Builder);
scaffold with php artisan make:filter. There is no ExistsFilter, ComparisonFilter,
IriFilter or FreeTextQueryFilter in the Eloquent set — nativeType on a parameter
is also unused (use BooleanFilter for booleans). #[ApiFilter] is not the Laravel
idiom; models declare #[QueryParameter] directly.
Archivos de esta skill
1Preguntas sobre la skill api-filter
¿Cómo instalo la skill api-filter en Claude Code?
Ejecuta npx degit api-platform/skillset/skills/api-filter ~/.claude/skills/api-filter. Claude Code carga las skills desde ~/.claude/skills (todos los proyectos) o .claude/skills (un proyecto) y usa una skill cuando su descripción coincide con la tarea.
¿Qué clientes pueden usar la skill api-filter?
Cualquier cliente que lea el formato Agent Skills: Claude Code, Codex, Gemini CLI y claude.ai (subir como ZIP). Los scripts de la skill se ejecutan solo donde el cliente permite la ejecución de código.
¿Cómo reemplazo el atributo #[ApiFilter] que está marcado como obsoleto?
Debes migrar al uso del enfoque QueryParameter dentro del array de parámetros de la operación, mapeando los filtros heredados a sus reemplazos canónicos de propósito único.
¿Cómo puedo implementar el filtrado de booleanos o enteros de la nueva forma canónica?
En lugar de usar un BooleanFilter dedicado, utiliza ExactFilter y declara el tipo nativo mediante TypeInfo de Symfony para asegurar un casting correcto.
¿Este SKILL es compatible con Laravel Eloquent?
Sí, pero debes usar las clases de filtrado específicas de Eloquent proporcionadas por ApiPlatformLaravelEloquent en lugar de las clases de Doctrine.