Навык operations
Настраивает жизненный цикл операций API, выражения безопасности, группы валидации и ограничения на уровне параметров для RESTful эндпоинтов.
- Звёзды на GitHub
- 29
- Файлы
- 1
- Последний коммит
- 22 окт. 2026 г.
- Лицензия
- —
- Разрешённые инструменты
- —
Что делает навык operations?
operations — это Agent Skill. Настраивает жизненный цикл операций API, выражения безопасности, группы валидации и ограничения на уровне параметров для RESTful эндпоинтов.
Сводка сгенерирована из SKILL.md навыка.
О skill operations
Этот SKILL позволяет разработчикам, использующим API Platform, настраивать жизненный цикл операций API, безопасность и валидацию для RESTful эндпоинтов. Он обеспечивает детальный контроль над фазами чтения и записи запроса, позволяя переключать провайдеры (providers) и процессоры (processors) для выполнения таких задач, как скачивание файлов или кастомная логика upsert. Разработчики могут использовать его для управления разделением CQRS, явно устанавливая флаги чтения и записи для различных HTTP-методов.
Помимо управления жизненным циклом, этот SKILL предоставляет инструменты для защиты эндпоинтов с помощью Symfony ExpressionLanguage для контроля доступа на основе ролей или объектов. Он также обеспечивает безопасность на уровне параметров запроса и заголовков. Для обеспечения целостности данных поддерживаются группы валидации, позволяющие различать ограничения при создании и обновлении, а также сбор ошибок при денормализации. Кроме того, инструмент позволяет управлять устареванием (deprecation) эндпоинтов через специальные заголовки и предоставляет рекомендации по обработке вложенных PATCH-запросов в сценариях JSON merge-patch.
Что агент может делать с ним
- 1Ограничение доступа к эндпоинту по ролямAI-агент может настроить POST-операцию так, чтобы её могли выполнять только пользователи с правами администратора.
- 2Применение различных правил валидацииРазработчик может дать агенту инструкцию использовать специфические группы валидации для создания и для обновления ресурса пользователя.
- 3Защита конкретных параметров запросаВы можете запросить проверку конкретного параметра запроса с помощью выражения безопасности перед запуском провайдера.
- 4Уведомление об устаревании APIАгент может добавить причины устаревания и даты прекращения поддержки (sunset dates) к существующему ресурсу, чтобы уведомить клиентов о предстоящих изменениях.
- 5Включение детальной отчетности об ошибкахРазработчик может настроить API так, чтобы оно возвращало все ошибки в некорректных полях сразу, а не останавливалось на первой найденной ошибке.
Написано на основе skill SKILL.md. Каждый сценарий использования проверен по цитате из него.
Как установить навык operations
Каждая команда копирует папку навыка в каталог навыков клиента. Перезапустите клиент или начните новую сессию, чтобы загрузить его.Установка навыка operations в Плагин
/plugin marketplace add api-platform/skillset /plugin install api-platform@api-platform-skillset
Установка навыка operations в Claude Code
~/.claude/skills/operations/SKILL.md
$ npx degit api-platform/skillset/skills/operations ~/.claude/skills/operationsУстановка навыка operations в Claude Code (project)
.claude/skills/operations/SKILL.md
$ npx degit api-platform/skillset/skills/operations .claude/skills/operationsУстановка навыка operations в Codex
~/.agents/skills/operations/SKILL.md
$ npx degit api-platform/skillset/skills/operations ~/.agents/skills/operationsУстановка навыка operations в Gemini CLI
~/.gemini/skills/operations/SKILL.md
$ npx degit api-platform/skillset/skills/operations ~/.gemini/skills/operationsУстановка навыка operations в Claude.ai
npx degit api-platform/skillset/skills/operations operations && zip -r operations.zip operations # claude.ai → Customize → Skills → + → Create skill → Upload a skill → operations.zip
SKILL.md
Открыть на GitHubOperations: Security, Validation & Lifecycle
Operation-level configuration that sits between the resource shape (see api-resource) and the read/write logic (see state-provider / state-processor).
Read & write phases (the provider/processor lifecycle)
Every operation runs two phases, each toggled by a boolean flag:
| Phase | Flag | Runs | Maps to (CQRS) |
|---|---|---|---|
| Read | read |
a provider fetches the data | Query |
| Write | write |
a processor persists / acts on the data | Command |
A full request is read → deserialize → validate → write → serialize. The provider
supplies the object the rest of the chain operates on; the processor performs the
side effect (persist, delete, send mail, build a file). This is API Platform's CQRS
split: GET-style reads go through a provider, state changes go through a
processor.
The flags default from the request, not the verb
You leave read/write unset and API Platform resolves them at runtime from the
HTTP request (see MainController / WriteListener in core):
writedefaults to "the method is not safe" —falseforGET/HEAD,trueforPOST,PUT,PATCH,DELETE.readdefaults to "the operation has URI variables, or the method is safe" — so item operations (which carry{id}) and allGETs read, but a collectionPOST(no URI variables, unsafe) does not.
| Operation | read |
write |
|---|---|---|
Get (item) |
true (has {id}) |
false |
GetCollection |
true (safe) |
false |
Post (collection) |
false (no URI vars, unsafe) |
true |
Put, Patch (item) |
true (has {id}) |
true |
Delete (item) |
true (has {id}) |
true |
So a Get skips the processor by default, and a collection Post runs a processor
without a provider. Override either flag to decouple the phase from this default:
// Run a processor on a GET (file download, report generation, counter bump):
new Get(
uriTemplate: '/orders/{id}/download',
write: true, // turn the write phase ON — processor now fires
processor: OrderDownloadProcessor::class,
)
// Skip the built-in fetch on an item write (upsert: processor handles a missing row):
new Put(
read: false, // no provider runs; $data comes from deserialization only
processor: UpsertProcessor::class,
)
write: true is the common case: a Get whose write defaults to false would
never invoke its processor — flipping the flag is what enables it. Conversely
read: false stops the built-in provider on an item operation from a needless fetch.
Securing operations
The security attribute takes a Symfony ExpressionLanguage string evaluated
before the operation runs. Available variables: user, object (item operations),
request parameters when explicitly exposed.
Role-based
#[ApiResource(
operations: [
new GetCollection(),
new Post(security: "is_granted('ROLE_ADMIN')"),
]
)]
class Invoice {}
Object-based (item operations)
object is the fetched resource — use it for ownership checks on Get, Put,
Patch, Delete:
new Get(security: "object.getOwner() == user")
new Patch(security: "object.getOwner() == user or is_granted('ROLE_ADMIN')")
securityPostDenormalize runs after the request body is applied — use it when the
decision depends on incoming values (e.g. preventing privilege escalation on PATCH).
Parameter-based
Each parameter carries its own security expression, where the parameter name
becomes a variable bound to the submitted value. Declare them in parameters as
QueryParameter or HeaderParameter:
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\HeaderParameter;
use ApiPlatform\Metadata\QueryParameter;
use Symfony\Component\TypeInfo\Type\BuiltinType;
use Symfony\Component\TypeInfo\TypeIdentifier;
#[GetCollection(
parameters: [
'name' => new QueryParameter(security: 'is_granted("ROLE_ADMIN")'),
'auth' => new HeaderParameter(security: '"secured" == auth', nativeType: new BuiltinType(TypeIdentifier::STRING)),
'secret' => new QueryParameter(security: '"secured" == secret', nativeType: new BuiltinType(TypeIdentifier::STRING)),
],
)]
?name=foo evaluates is_granted("ROLE_ADMIN") (403 otherwise); the auth header
or ?secret=… must equal secured or the request is rejected. The parameter is
only checked when present — an absent or value-less parameter passes.
For query-level data isolation (multi-tenant, soft-delete) that must apply to every query regardless of operation, use a Doctrine extension or link handler instead — see securing-collections.
securityonly guards an already-fetched object; it does not scope collections.
Validation
API Platform runs Symfony's Validator on the deserialized object before the processor. Constraints live on the resource/input DTO (see custom-validator).
Validation groups per operation
#[ApiResource(
operations: [
new Post(validationContext: ['groups' => ['Default', 'user:create']]),
new Patch(validationContext: ['groups' => ['Default', 'user:update']]),
]
)]
#[Assert\NotBlank(groups: ['user:create'])] // required on create only
#[Assert\Email(groups: ['user:create', 'user:update'])] // checked on both
public ?string $email = null;
Collect denormalization errors
By default a type mismatch in the body throws on the first bad field. Enable
collect_denormalization_errors to report every malformed field at once in the 422
violations array:
#[Post(validationContext: ['collect_denormalization_errors' => true])]
Each malformed field becomes a violations entry with a propertyPath, a
This value should be of type … message, and a hint explaining the failure.
Validating query parameters
Attach constraints to a QueryParameter (or HeaderParameter); invalid values
yield 422 before the provider runs:
use ApiPlatform\Metadata\QueryParameter;
use Symfony\Component\Validator\Constraints as Assert;
#[GetCollection(
parameters: [
'page' => new QueryParameter(constraints: [new Assert\Positive()]),
],
)]
Deprecating endpoints
deprecationReason adds a Deprecation header; sunset adds a Sunset header
with the removal date. Apply at resource or operation level.
#[ApiResource(
deprecationReason: 'Use /v2/invoices instead.',
sunset: '2026-01-01T00:00:00+00:00',
)]
class Invoice {}
deprecationReason emits a Deprecation header and sunset a Sunset header. To
also advertise a migration doc, add an explicit operation links: entry —
new Link('deprecation', 'https://…') renders Link: <…>; rel="deprecation".
Nested PATCH gotcha
With application/merge-patch+json, to update an existing nested resource you
must include its identifier. Omitting it makes the serializer treat the nested
object as new (and attempt to create it):
{ "shippingAddress": { "id": 12, "city": "Lyon" } }
Without "id", API Platform tries to create a new Address rather than patch #12.
Laravel
Per-operation metadata (security, validationContext groups, collect_denormalization_errors,
deprecationReason/sunset, parameter validation/security) is mostly shared, but
auth and validation wiring differ:
- Authorization integrates with Laravel policies, not Symfony voters. Once a
policy exists, API Platform auto-maps operations to methods: GET collection →
viewAny, GET →view, POST →create, PATCH/PUT →update(PUT →createif absent), DELETE →delete. Override the mapping with apolicy:property on the operation:new Patch(policy: 'myCustomPolicy'). ThesecurityExpressionLanguage string also works. - Authentication / middleware is attached with the Laravel
middleware:property per operation (new Patch(middleware: 'auth:sanctum')) or globally underdefaults.middlewareinconfig/api-platform.php. - Validation uses Laravel
rules(array / closure /FormRequest) per resource or operation rather than SymfonyvalidationContextgroups — see the custom-validator Laravel section.AuthenticationException→ 401 andAuthorizationException→ 403 are mapped by default in the config'sexception_to_status. - Query/header
Parameterconstraintsare Laravel validation rule strings (e.g.'min:2'), not Symfony constraints.
Checklist
- Write operations restricted with
security/securityPostDenormalize - Collection isolation handled by an extension, not
security(see securing-collections) -
validationContextgroups split create vs update constraints -
collect_denormalization_errorsenabled where clients need full error lists - Query parameters carry validation constraints
- Deprecated endpoints set
deprecationReason+sunset
Файлы в этом навыке
1Вопросы о навыке operations
Как установить навык operations в Claude Code?
Выполните npx degit api-platform/skillset/skills/operations ~/.claude/skills/operations. Claude Code загружает навыки из ~/.claude/skills (все проекты) или .claude/skills (один проект) и использует навык, когда его описание соответствует задаче.
Какие клиенты могут использовать навык operations?
Любой клиент, который читает формат Agent Skills: Claude Code, Codex, Gemini CLI и claude.ai (загрузить как ZIP). Скрипты в навыке выполняются только там, где клиент разрешает выполнение кода.
Как ограничить доступ к эндпоинту только для администраторов?
Вы можете использовать атрибут security со строкой Symfony ExpressionLanguage, например is_granted('ROLE_ADMIN').
Как применять разные правила валидации для создания и обновления ресурса?
Вы можете использовать группы валидации (validation groups) внутри validationContext операции, чтобы указать разные наборы ограничений.
Как вернуть сразу все ошибки в некорректных полях, а не только первую?
Включите флаг collect_denormalization_errors в validationContext, чтобы возвращать полный список нарушений в ответе 422.