diff --git a/.github/ISSUE_TEMPLATE/1-feature.yml b/.github/ISSUE_TEMPLATE/1-feature.yml
index 3959b5f0..54b68ea7 100644
--- a/.github/ISSUE_TEMPLATE/1-feature.yml
+++ b/.github/ISSUE_TEMPLATE/1-feature.yml
@@ -17,6 +17,7 @@ body:
- Authoring library
- Compiler
- Emulator library
+ - Documentation
validations:
required: true
- type: input
diff --git a/.github/ISSUE_TEMPLATE/2-bug.yml b/.github/ISSUE_TEMPLATE/2-bug.yml
index 342c0d0d..5f11d634 100644
--- a/.github/ISSUE_TEMPLATE/2-bug.yml
+++ b/.github/ISSUE_TEMPLATE/2-bug.yml
@@ -42,6 +42,7 @@ body:
- Authoring library
- Compiler
- Emulator library
+ - Documentation
validations:
required: true
- type: input
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 30fead8d..099341c7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -31,6 +31,10 @@ This will greatly increase alignment of your PR with the project goals and reduc
For more information on how to set up the development environment,
see [Development environment setup](docs/DevEnvironmentSetup.md).
+### Implementation guides
+
+ - [Add new policy guide](docs/AddPolicyGuide.md)
+
## License
This project welcomes contributions and suggestions. Most contributions require you to
diff --git a/README.md b/README.md
index 959f5a00..69e7efdb 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,8 @@ The policy toolkit changes that. It allows you to write policy documents in C# l
## Documentation
+:exclamation: Packages are only avaliable for download from github release. We are working to bring them to public nuget.
+
#### Azure API Management policy toolkit documentation for users.
* [Quick start](docs/QuickStart.md)
* [Available policies](docs/AvailablePolicies.md)
diff --git a/docs/AddPolicyGuide.md b/docs/AddPolicyGuide.md
new file mode 100644
index 00000000..9ab80e3a
--- /dev/null
+++ b/docs/AddPolicyGuide.md
@@ -0,0 +1,150 @@
+# Contributing a new policy (feature)
+
+This guide outlines the steps to support a new policy, or new capabilities for an existing policy.
+
+All contributions should follow the steps provided in this guide to support a policy (feature) and its configuration.
+
+If you cannot follow the defined process, please open an issue to discuss before implementing it.
+
+## TL;DR
+
+When adding a new policy, you will typically need to create or modify the following files:
+
+- **Introduce the configuration**: `src/Authoring/Configs/YourPolicyConfig.cs` (Exampe: `RateLimitConfig.cs`)
+- **Enable using in respective section or fragment**: `src/Authoring/IInboundContext.cs` (or other context)
+- **Support compilation**: `src/Core/Compiling/Policy/YourPolicyCompiler.cs` (Exampe: `RateLimitCompiler.cs`)
+- **Provide automated tests**: `test/Test.Core/Compiling/YourPolicyTests.cs` (Exampe: `RateLimitTests.cs`)
+- **Document your policy**: `docs/AvailablePolicies.md`
+
+We recommend using existing policies as detailed examples, such as `RateLimit` or `Quota` policies. These contain all possible aspects of a policy compilation implementation.
+
+## Steps to add a new policy
+
+- Create `src/Authoring/Configs/YourPolicyConfig.cs` as a public record.
+ - Required parameters as `required` `init` properties
+ - Optional properties should be `nullable`
+ - Properties allowing policy expressions should have `[ExpressionAllowed]` attribute assigned.
+ - Add XML documentation for the record and its properties.
+
+```csharp
+ ///
+ /// Description of config.
+ ///
+ public record YourPolicyConfig
+ {
+ ///
+ /// Description of your property.
+ ///
+ [ExpressionAllowed]
+ public required string Property { get; init; }
+
+ ///
+ /// Optional property description.
+ ///
+ [ExpressionAllowed]
+ public int? OptionalProperty { get; init; }
+
+ // Add more properties as needed.
+ }
+```
+
+- Add a method signature to section context interfaces in which policy is avaliable (e.g. `src/Authoring/IInboundContext.cs`).
+ Add method to policy fragment context interface to make policy avaliable in policy fragment.
+ Make sure to add XML documentation.
+
+```csharp
+ ///
+ /// Description of your policy.
+ ///
+ /// Configuration for the YourPolicy policy.
+ ///
+ ///
+ void YourPolicy(YourPolicyConfig config);
+```
+
+- Create compiler class `src/Core/Compiling/Policy/YourPolicyCompiler.cs` implementing `IMethodPolicyHandler`.
+ This class will be responsible for translating the C# method call into the corresponding XML policy element.
+ - Make sure that the class is `public` and in `Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling.Policy` namespace.
+ This is required for the automatic adding your policy compiler to the compilation.
+ - Implement the `Handle` method to extract parameters from the method invocation and construct the XML element.
+ - Use `TryExtractingConfigParameter` to extract the config object into initialization object.
+ - Use `AddAttribute` extension method to add attributes to the XML element.
+ - Report diagnostics for missing required parameters using `context.ReportDiagnostic`.
+ For avaliable errors see `CompilationErrors.cs` file.
+ - For complex policies with sub elements, refer to existing compilers for guidance (eg. RateLimitCompiler).
+
+```csharp
+namespace Microsoft.Azure.ApiManagement.PolicyToolkit.Compiling.Policy;
+
+public class YourPolicyCompiler : IMethodPolicyHandler
+{
+ public string MethodName => nameof(IInboundContext.YourPolicy);
+
+ public void Handle(IDocumentCompilationContext context, InvocationExpressionSyntax node)
+ {
+ if (!node.TryExtractingConfigParameter(context, "your-policy", out var values))
+ {
+ return;
+ }
+
+ var element = new XElement("your-policy");
+
+ if (!element.AddAttribute(values, nameof(YourPolicyConfig.Property), "propery"))
+ {
+ context.Report(Diagnostic.Create(
+ CompilationErrors.RequiredParameterNotDefined,
+ node.GetLocation(),
+ "your-policy",
+ nameof(YourPolicyConfig.Property)
+ ));
+ return;
+ }
+
+ element.AddAttribute(values, nameof(YourPolicyConfig.OptionalProperty), "optional-property");
+
+ context.AddPolicy(element);
+ }
+}
+```
+
+- Add tests to `test/Test.Core/Compiling/YourPolicyTests.cs`.
+ - Use a `[DataRow]` for each test case, following the pattern of existing tests.
+ - Check that compiler
+ - handles compiling policy in all of sections which you added the method to
+ - required aparameters with constant values
+ - optional parameters with constant values
+ - expressions for properties which define [ExpressionAllowed] attribute
+
+```csharp
+[TestClass]
+public class YourPolicyTests : PolicyCompilerTestBase
+{
+ [TestMethod]
+ [DataRow(
+ """
+ [Document]
+ public class PolicyDocument : IDocument
+ {
+ public void Inbound(IInboundContext context) {
+ context.YourPolicy(new YourPolicyConfig()
+ {
+ Property = "Value"
+ });
+ }
+ }
+ """,
+ """
+
+
+
+
+
+ """)]
+ public void ShouldCompileYourPolicy(string code, string expectedXml)
+ {
+ code.CompileDocument().Should().BeSuccessful().And.DocumentEquivalentTo(expectedXml);
+ }
+}
+```
+
+- Update `docs/AvailablePolicies.md` to include your new policy in the list of implemented policies.
diff --git a/docs/AvailablePolicies.md b/docs/AvailablePolicies.md
index f9139998..099f3ec6 100644
--- a/docs/AvailablePolicies.md
+++ b/docs/AvailablePolicies.md
@@ -1,57 +1,103 @@
# Available Policies
-The Project is in the development stage.
-That means that not all policies are implemented yet.
-In this document, you can find a list of implemented policies. For policy details, see the Azure API Management [policy reference](https://learn.microsoft.com/azure/api-management/api-management-policies).
-
-#### :white_check_mark: Implemented policies
-
-* authentication-basic
-* authentication-certificate
-* authentication-managed-identity
-* azure-openai-emit-token-metric
-* azure-openai-semantic-cache-lookup
-* azure-openai-semantic-cache-store
-* base
-* cache-lookup
-* cache-lookup-value
-* cache-remove-value
-* cache-store
-* cache-store-value
-* check-header
-* choose
-* cors
-* emit-metric
-* find-and-replace
-* forward-request
-* ip-filter
-* json-to-xml
-* jsonp
-* llm-emit-token-metric
-* llm-semantic-cache-lookup
-* llm-semantic-cache-store
-* mock-response
-* quota
-* rate-limit
-* rate-limit-by-key
-* return-response
-* rewrite-uri
-* send-request
-* set-backend-service
-* set-body
-* set-header
-* set-method
-* set-query-parameter
-* set-variable
-* validate-jwt
-
-Policies not listed here are not implemented yet, we are curious to know which [ones you'd like to use and are happy to review contributions](./../CONTRIBUTING.md).
-
-## InlinePolicy
-
-InlinePolicy is a workaround until all the policies are implemented.
+This document lists policy elements that the toolkit's authoring and compiler support by mapping C# APIs to Azure API
+Management policy elements. The list below was generated from the public authoring interfaces (
+inbound/outbound/backend/on-error/fragment contexts) and reflects which policies the toolkit can compile into XML.
+
+If a policy you need is missing you can either:
+
+- Use `InlinePolicy(...)` to insert raw XML into the compiled document, or
+- Open an issue / contribute the feature (learn more in [our contribution guide](../CONTRIBUTING.md)).
+
+Notes:
+
+- The C# compiler maps C# constructs to policy constructs. For example, if/else in C# is compiled to the `choose`
+ policy (with `when` / `otherwise`).
+- `InlinePolicy(string)` allows inserting arbitrary XML when a policy isn't implemented as a first-class API.
+
+## Implemented policies
+
+- authentication-basic
+- authentication-certificate
+- authentication-managed-identity
+- azure-openai-emit-token-metric
+- azure-openai-semantic-cache-lookup
+- azure-openai-semantic-cache-store
+- azure-openai-token-limit
+- base
+- cache-lookup
+- cache-lookup-value
+- cache-remove-value
+- cache-store
+- cache-store-value
+- check-header
+- choose (implemented via C# if/else -> choose/when/otherwise)
+- cors
+- cross-domain
+- emit-metric
+- find-and-replace
+- forward-request
+- get-authorization-context
+- include-fragment
+- inline-policy (method to insert raw XML)
+- invoke-dapr-binding (publish/send to Dapr bindings)
+- ip-filter
+- json-to-xml
+- jsonp
+- limit-concurrency
+- llm-content-safety
+- llm-emit-token-metric
+- llm-semantic-cache-lookup
+- llm-semantic-cache-store
+- llm-token-limit
+- log-to-eventhub
+- mock-response
+- proxy
+- publish-to-dapr
+- quota
+- quota-by-key
+- rate-limit
+- rate-limit-by-key
+- redirect-content-urls
+- remove-header (via SetHeader/RemoveHeader APIs)
+- remove-query-parameter (via SetQueryParameter/Remove APIs)
+- return-response
+- retry
+- rewrite-uri
+- send-one-way-request
+- send-request
+- set-backend-service
+- set-body
+- set-header
+- set-header-if-not-exist
+- set-method
+- set-query-parameter
+- set-query-parameter-if-not-exist
+- set-status
+- set-variable
+- trace
+- validate-azure-ad-token
+- validate-client-certificate
+- validate-content
+- validate-headers
+- validate-jwt
+- validate-odata-request
+- validate-parameters
+- validate-status-code
+- wait
+- xml-to-json
+- xsl-transform
+
+## How to work around missing policies
+
+InlinePolicy is a workaround until all the policies are implemented or new policies are not added yet to toolkit.
It allows you to include policy not implemented yet to the document.
```csharp
c.InlinePolicy("");
```
+
+## Contributing
+
+If you'd like a specific policy implemented natively in the toolkit, please open an issue or a pull request in this
+repository. See [CONTRIBUTING.md](../CONTRIBUTING.md) and [Add new policy guide](AddPolicyGuide.md) for guidance.
diff --git a/docs/QuickStart.md b/docs/QuickStart.md
index 55bc45d5..56ad5a51 100644
--- a/docs/QuickStart.md
+++ b/docs/QuickStart.md
@@ -36,17 +36,19 @@ We will cover the following topics:
+
+
```
-5. Add Azure API Management policy toolkit library by running
+5. Add Azure API Management policy authoring toolkit library by running
```shell
cd ./Contoso.Apis.Policies
dotnet add package Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring
```
6. Open the solution in your IDE of choice. We
- tested [Visual Studio ](https://visualstudio.microsoft.com), [Raider](https://www.jetbrains.com/rider/), [Visual Studio Code](https://code.visualstudio.com/)
+ tested [Visual Studio ](https://visualstudio.microsoft.com), [Rider](https://www.jetbrains.com/rider/), [Visual Studio Code](https://code.visualstudio.com/)
with [C# Dev Kit](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csdevkit),
but any IDE with C# support should work.
@@ -62,10 +64,10 @@ dotnet new class -n ApiOperationPolicy
```
The class in the file should inherit from `IDocument` interface and have `Document` attribute
-from `Azure.ApiManagement.PolicyToolkit.Authoring` namespace.
+from `Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring` namespace.
```csharp
-using Azure.ApiManagement.PolicyToolkit.Authoring;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring;
namespace Contoso.Apis.Policies;
@@ -121,14 +123,14 @@ cd .. # Go to solution folder if not already there
dotnet tool install Azure.ApiManagement.PolicyToolkit.Compiling
````
-After the installation, the compiler should be available in the project folder.
-Now lets run the compiler to generate policy document. Execute compiler command in the solution folder.
+After the installation, the compiler should be available in the project folder as the `azure-apim-policy-compiler` command.
+Now let's run the compiler to generate policy document. Execute compiler command in the solution folder.
```shell
dotnet azure-apim-policy-compiler --s .\Contoso.Apis.Policies --o . --format true
-```
+```
-The compiler is a dotnet tool named `azure-apim-policy-compiler`. The `--s` parameter is a source folder with policy documents.
+The compiler is a dotnet tool whose command name is `azure-apim-policy-compiler`. The `--s` parameter is a source folder with policy documents.
The `--o` parameter is an output folder for generated policy documents. The `--format` parameter is a flag which tells
the compiler to format the generated document.
@@ -169,8 +171,8 @@ If a request comes from other IP addresses it should use `Bearer` token received
For every request we want to add header with the user id.
```csharp
-using Azure.ApiManagement.PolicyToolkit.Authoring;
-using Azure.ApiManagement.PolicyToolkit.Authoring.Expressions;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring.Expressions;
namespace Contoso.Apis.Policies;
@@ -209,7 +211,7 @@ Let's unpack the code above it:
expression
* Every method, other than section method are treated as expressions. They need to accept one parameter of type
`IExpressionContext`
- with name `context`. Type is available in `Azure.ApiManagement.PolicyToolkit.Authoring.Expressions` namespace.
+ with name `context`. Type is available in `Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring.Expressions` namespace.
* `IExpressionContext` type contains the same properties as `context` object in policy expressions.
* `AuthenticationBasic` method is mapped to `authentication-basic` policy.
* `AuthenticationManagedIdentity` method is mapped to `authentication-managed-identity` policy.
@@ -269,7 +271,7 @@ the following commands.
dotnet new mstest --output Contoso.Apis.Policies.Tests
dotnet sln add ./Contoso.Apis.Policies.Tests
cd Contoso.Apis.Policies.Tests
-dotnet add package Azure.ApiManagement.PolicyToolkit.Testing
+dotnet add package Microsoft.Azure.ApiManagement.PolicyToolkit.Testing
dotnet add reference ..\Contoso.Apis.Policies
dotnet new class -n ApiOperationPolicyTest
```
@@ -279,7 +281,7 @@ Perfect! Now we can write a test for `IsCompanyIP` method in the class.
```csharp
using Contoso.Apis.Policies;
-using Azure.ApiManagement.PolicyToolkit.Testing.Expressions;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Testing.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;
@@ -307,7 +309,7 @@ Let's unpack the code above:
* Test class is a standard MSTest class with one test method. You can use your favorite testing framework in place of MSTest. Policy framework is not dependent on any testing framework.
* `MockExpressionContext` is a class which is used to mock request context. It is available in
- `Azure.ApiManagement.PolicyToolkit.Testing.Expressions` namespace. It implements `IExpressionContext`
+ `Microsoft.Azure.ApiManagement.PolicyToolkit.Testing.Expressions` namespace. It implements `IExpressionContext`
interface and exposes helper properties to set up request context.
* `context.MockRequest.IpAddress = "10.0.0.12"` is setting a IpAddress for request.
diff --git a/src/Authoring/README.md b/src/Authoring/README.md
index 733a74d2..a605b119 100644
--- a/src/Authoring/README.md
+++ b/src/Authoring/README.md
@@ -20,7 +20,8 @@ dotnet add package Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring
### Write your first policy
```csharp
-using Azure.ApiManagement.PolicyToolkit.Authoring;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Authoring.Expressions;
namespace Contoso.Apis.Policies;
diff --git a/src/Compiling/README.md b/src/Compiling/README.md
index 9d540082..4fec576d 100644
--- a/src/Compiling/README.md
+++ b/src/Compiling/README.md
@@ -1,27 +1,15 @@
-# Microsoft Azure ApiManagement Policy Toolkit policy compiler tool
+# Azure API Management Policy Toolkit Compiler
-Microsoft Azure API Management is a hybrid, multicloud management platform for APIs across all environments. As a
-platform-as-a-service, API Management supports the complete API lifecycle.
-
-This library contains .net tool which transforms policies wrote in C# to format accepted by Microsoft Azure Api
-Management.
-
-## Getting started
-
-### Install compiler CLI tool
+This project builds a dotnet tool which can compile C# policy documents into Azure API Management XML (rawxml / Razor)
+policy documents.
+## Install
Install the Microsoft Azure Api Management Policy Toolkit compiler CLI tool with [NuGet][nuget]:
-```dotnetcli
+```shell
dotnet tool install Azure.ApiManagement.PolicyToolkit.Compiling
```
-### Compile the policy
-
-```bash
-dotnet azure-apim-policy-compiler --s .\PATH\TO\SOURCE\FOLDER --o .\PATH\TO\OUTPUT\FOLDER
-```
-
### Inspect generated policy
```cshtml
diff --git a/src/Testing/README.md b/src/Testing/README.md
index 80a969b6..125f486f 100644
--- a/src/Testing/README.md
+++ b/src/Testing/README.md
@@ -13,14 +13,14 @@ expression and policy documents wrote in C# for Microsoft Azure Api Management.
Install the Microsoft Azure Api Management Policy Toolkit test library with [NuGet][nuget]:
```dotnetcli
-dotnet tool install Azure.ApiManagement.PolicyToolkit.Testing
+dotnet add package Microsoft.Azure.ApiManagement.PolicyToolkit.Testing
```
### Write test
```cs
using Contoso.Apis.Policies;
-using Azure.ApiManagement.PolicyToolkit.Testing.Expressions;
+using Microsoft.Azure.ApiManagement.PolicyToolkit.Testing.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Contoso.Apis.Policies.Tests;
@@ -31,6 +31,7 @@ public class ApiOperationPolicyTest
[TestMethod]
public void TestHelloFromExpression()
{
+ var context = new MockExpressionContext();
Assert.AreEqual("World", ApiOperationPolicy.HelloFromExpression(context));
}
}