Skip to main content

policy-authoring

Conventions and patterns for creating policy authoring types in the Azure API Management policy toolkit. Use this skill when creating or modifying config records in src/Authoring/Configs/ or adding methods to section context interfaces.

معلومات المصدر

المستودع
Azure/azure-api-management-policy-toolkit
آخر نشاط في المصدر
٨ مارس ٢٠٢٦ في ١٨:٥٣
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٩٥
التفرعات
٣٧

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
policy-authoring
description
Conventions and patterns for creating policy authoring types in the Azure API Management policy toolkit. Use this skill when creating or modifying config records in src/Authoring/Configs/ or adding methods to section context interfaces.
# Policy Authoring Patterns This skill describes how to create authoring types (config records and context interface methods) for policies in the Azure API Management policy toolkit. ## Config Record — `src/Authoring/Configs/{PolicyName}Config.cs` ### File Template ```csharp // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. namespace Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring; /// <summary> /// Configuration for the {xml-element-name} policy.<br/> /// {Brief description of what the policy does.} /// </summary> public record {PolicyName}Config { /// <summary> /// {Property description}. Policy expressions are allowed. /// </summary> [ExpressionAllowed] public required {Type} {PropertyName} { get; init; } /// <summary> /// Optional. {Property description}. /// </summary> public {Type}? {OptionalPropertyName} { get; init; } } ``` ### Related Attributes - **`[Document]`** (`src/Authoring/Attributes/DocumentAttribute.cs`) — Marks a class as a policy document. Optional `name` parameter; `Scope` and `Type` properties control document scope and type. - **`[Expression]`** (`src/Authoring/Attributes/ExpressionAttribute.cs`) — Marks a method as a policy expression (captures source file path via `[CallerFilePath]`). Used by the compiler to identify expression helper methods. - **`[ExpressionAllowed]`** (`src/Authoring/Attributes/ExpressionAllowedAttribute.cs`) — Marks config properties or parameters that accept policy expressions. ### Property Rules - **Required properties**: use the `required` keyword + `init` setter. - **Optional properties**: use a nullable type (`?`) + `init` setter. Do **not** use `required`. - **Expression-enabled properties**: decorate with `[ExpressionAllowed]` attribute. Add "Policy expressions are allowed." to the XML doc. - **Constrained properties** (enums, allowed values): use either: - A C# `enum` type (preferred for fixed, type-safe values) - A `string` property with XML doc listing allowed values (for values documented outside code) - Validation is applied at **compilation time** by the compiler class, **not at authoring time**. The config record accepts any value; the compiler reports diagnostics if invalid. - **Sub-configs** (child element arrays): define as separate `public record` types in the same file. - **Sub-config naming convention**: Use descriptive nouns that reflect their purpose (e.g., `ApiRateLimit`, `AddressRange`, `MatchCondition`), not generic names like `Item` or `Element`. - **Every public type and member** must have `/// <summary>` XML documentation covering: - Purpose - Required vs optional status - Default value (if any) - Expression support (yes/no) - Allowed values / enums (if applicable) ### Real Examples **Simple attributes with expression support** — `RateLimitByKeyConfig.cs`: ```csharp public record RateLimitByKeyConfig { [ExpressionAllowed] public required int Calls { get; init; } [ExpressionAllowed] public required int RenewalPeriod { get; init; } [ExpressionAllowed] public required string CounterKey { get; init; } [ExpressionAllowed] public bool? IncrementCondition { get; init; } public string? RetryAfterHeaderName { get; init; } } ``` **Nested sub-records** — `RateLimitConfig.cs`: ```csharp public record RateLimitConfig { public required int Calls { get; init; } public required int RenewalPeriod { get; init; } public string? RetryAfterHeaderName { get; init; } public ApiRateLimit[]? Apis { get; init; } } public record ApiRateLimit : EntityLimitConfig { public OperationRateLimit[]? Operations { get; init; } } public abstract record EntityLimitConfig { public string? Name { get; init; } public string? Id { get; init; } public required int Calls { get; init; } public required int RenewalPeriod { get; init; } } ``` **Typed child arrays** — `IpFilterConfig.cs`: ```csharp public record IpFilterConfig { /// <summary> /// The action to apply: 'allow' or 'deny'. Policy expressions are allowed. /// </summary> [ExpressionAllowed] public required string Action { get; init; } /// <summary> /// Optional. IP addresses. Policy expressions are allowed. /// </summary> [ExpressionAllowed] public string[]? Addresses { get; init; } /// <summary> /// Optional. IP address ranges. /// </summary> public AddressRange[]? AddressRanges { get; init; } } /// <summary> /// An IP address range with 'from' and 'to' octets. /// </summary> public record AddressRange { /// <summary> /// The starting IP address. Policy expressions are allowed. /// </summary> [ExpressionAllowed] public required string From { get; init; } /// <summary> /// The ending IP address. Policy expressions are allowed. /// </summary> [ExpressionAllowed] public required string To { get; init; } } ``` **Constrained values with enum** — `AdvancedPolicyConfig.cs` (example pattern): ```csharp /// <summary> /// The caching behavior for the policy action. /// </summary> public enum CachingBehavior { /// <summary>Cache the response.</summary> Store, /// <summary>Reuse a cached response if available.</summary> Validate, /// <summary>Bypass cache entirely.</summary> Bypass } public record AdvancedPolicyConfig { /// <summary> /// Required. The caching behavior: 'Store', 'Validate', or 'Bypass'. /// </summary> public required CachingBehavior Behavior { get; init; } } ``` ## Context Interface Methods Add method signatures to the appropriate section interfaces. Policies may appear in one or more sections: - `src/Authoring/IInboundContext.cs` - `src/Authoring/IOutboundContext.cs` - `src/Authoring/IBackendContext.cs` - `src/Authoring/IOnErrorContext.cs` - `src/Authoring/IFragmentContext.cs` ### Method Signature Template ```csharp /// <summary> /// {Description of the policy behavior}.<br/> /// Compiled to <a href="{documentation-url}">{xml-element-name}</a> policy. /// </summary> /// <param name="config"> /// Configuration for the {xml-element-name} policy. /// </param> void {MethodName}({PolicyName}Config config); ``` ### Rules - The method name is PascalCase and matches the config name minus the `Config` suffix (e.g., `RateLimit` for `RateLimitConfig`). - All section interfaces extend `IHaveExpressionContext`, giving access to `ExpressionContext`. - For parameters that are expressions (not config objects), use `[ExpressionAllowed]` on the parameter itself. - Some policies use direct parameters instead of a config object (e.g., `void SetMethod(string method)`). Use this pattern only for policies with 1–2 simple parameters and no optional fields. ### `IFragmentContext` Duplication `IFragmentContext` currently duplicates method signatures from the section-specific interfaces (see the `//TODO` comment at the top of the file). **Every time you add a policy method to any section interface, you must also add the same signature to `IFragmentContext.cs`.** Copy the exact same method signature verbatim. Do not attempt to refactor this pattern.
عرض على GitHub