Version: 1.0.0
Last Updated: 2025-10-22
Status: AZAPI Provider Implementation
- Executive Summary
- Architecture Overview
- Core Components
- Package Structure
- Key Architectural Patterns
- Version Management System
- Resource Creation Flow
- Testing Architecture
- Multi-Language Support
- Design Principles
- Future Extensibility
The @microsoft/terraform-cdk-constructs package is a TypeScript-based library that provides Level 2 (L2) constructs for Azure infrastructure using the AZAPI provider. Version 1.0.0 represents a major architectural shift from AzureRM provider to AZAPI provider, enabling direct Azure REST API access without provider limitations.
- Direct API Access: Uses AZAPI provider for immediate access to new Azure features
- Version-Aware: Automatic API version management with migration guidance
- Multi-Language: JSII-compliant for TypeScript, Python, Java, and C#/.NET
- Self-Contained: Includes AZAPI provider bindings (no external generation needed)
- Production-Ready: Comprehensive testing with unit, integration, and E2E tests
graph TB
subgraph "User Layer"
A[TypeScript/Python/Java/C# Code]
end
subgraph "L2 Constructs Layer"
B[ResourceGroup]
C[StorageAccount]
D[Future Services]
end
subgraph "Core Framework Layer"
E[AzapiResource Base Class]
F[ApiVersionManager]
G[SchemaMapper]
end
subgraph "AZAPI Provider Layer"
H[AZAPI Resource]
I[AZAPI Data Sources]
J[Client Config]
end
subgraph "Azure Layer"
K[Azure REST APIs]
end
A --> B
A --> C
A --> D
B --> E
C --> E
D --> E
E --> F
E --> G
E --> H
H --> K
I --> K
J --> K
F -.Version Resolution.-> E
G -.Schema Validation.-> E
- User Layer: Developer code in multiple languages
- L2 Constructs Layer: High-level Azure service abstractions
- Core Framework Layer: Version management and validation
- AZAPI Provider Layer: Direct Azure API communication
- Azure Layer: Azure REST APIs
Location: src/core-azure/lib/azapi/azapi-resource.ts
The foundational abstract class for all Azure resources with version awareness.
- Version Resolution: Automatic latest version or explicit pinning
- Schema Management: Load and validate API schemas
- Property Processing: Transform and validate properties
- Migration Analysis: Detect breaking changes and provide guidance
- Resource Creation: Generate AZAPI Terraform resources
- Lifecycle Management: RBAC and diagnostic settings support
export abstract class AzapiResource extends Construct {
// Version management
public readonly resolvedApiVersion: string;
public readonly schema: ApiSchema;
public readonly versionConfig: VersionConfig;
// Abstract methods (must be implemented by subclasses)
protected abstract defaultVersion(): string;
protected abstract resourceType(): string;
protected abstract apiSchema(): ApiSchema;
protected abstract createResourceBody(props: any): any;
// Public API
public latestVersion(): string | undefined;
public supportedVersions(): string[];
public analyzeMigrationTo(targetVersion: string): MigrationAnalysis;
}Location: src/core-azure/lib/version-manager/api-version-manager.ts
Centralized registry for managing Azure API versions across all resource types.
- Version Registration: Store version metadata and schemas
- Version Resolution: Find latest/best version based on constraints
- Compatibility Analysis: Analyze migration paths between versions
- Lifecycle Tracking: Monitor version deprecation and sunset phases
export class ApiVersionManager {
// Singleton access
public static instance(): ApiVersionManager;
// Version registration
public registerResourceType(resourceType: string, versions: VersionConfig[]): void;
// Version queries
public latestVersion(resourceType: string): string | undefined;
public supportedVersions(resourceType: string): string[];
public versionConfig(resourceType: string, version: string): VersionConfig | undefined;
// Analysis
public analyzeMigration(resourceType: string, from: string, to: string): MigrationAnalysis;
public validateVersionSupport(resourceType: string, version: string): boolean;
}Location: src/core-azure/lib/azapi/schema-mapper/schema-mapper.ts
Property transformation and validation engine for API schemas.
- Property Transformation: Map properties between schema versions
- Validation: Comprehensive property validation with detailed errors
- Default Application: Inject default values from schemas
- Type Conversion: Convert between property types safely
export class SchemaMapper {
public static create(schema: ApiSchema): SchemaMapper;
// Transformation
public transformProperties(sourceProps: any, targetSchema: ApiSchema): any;
public mapProperty(name: string, value: any, target: PropertyDefinition): any;
// Validation
public validateProperties(properties: any): ValidationResult;
// Defaults
public applyDefaults(properties: any): any;
}Location: src/core-azure/lib/azapi/providers-azapi/
Pre-generated TypeScript classes for AZAPI provider resources and data sources.
- Resource: Main AZAPI resource for Azure API calls
- DataAzapiClientConfig: Azure subscription and tenant information
- DataAzapiResource: Read existing Azure resources
- ResourceAction: Invoke Azure resource actions
- UpdateResource: Update existing resources
- DataPlaneResource: Data plane operations
terraform-cdk-constructs/
├── src/
│ ├── index.ts # Main package entry point
│ │
│ ├── core-azure/ # Core framework
│ │ ├── index.ts # Core exports
│ │ └── lib/
│ │ ├── azapi/
│ │ │ ├── azapi-resource.ts # Base class for all resources
│ │ │ ├── azapi-exports.ts # Public API exports
│ │ │ ├── providers-azapi/ # AZAPI provider classes
│ │ │ └── schema-mapper/ # Property transformation
│ │ │ └── schema-mapper.ts
│ │ └── version-manager/ # Version management
│ │ ├── api-version-manager.ts
│ │ ├── version-manager.ts
│ │ └── interfaces/
│ │ └── version-interfaces.ts
│ │
│ ├── azure-resourcegroup/ # Resource Group construct
│ │ ├── index.ts
│ │ ├── lib/
│ │ │ ├── resource-group.ts # Implementation
│ │ │ └── resource-group-schemas.ts # API schemas
│ │ └── test/
│ │ ├── resource-group.spec.ts # Unit tests
│ │ └── resource-group.integ.ts # Integration tests
│ │
│ ├── azure-storageaccount/ # Storage Account construct
│ │ ├── index.ts
│ │ ├── lib/
│ │ │ ├── storage-account.ts
│ │ │ └── storage-account-schemas.ts
│ │ └── test/
│ │ ├── storage-account.spec.ts
│ │ └── storage-account.integ.ts
│ │
│ ├── testing/ # Testing utilities
│ │ └── index.ts # Test helpers
│ │
│ └── util/ # Utility functions
│ ├── azureTenantIdHelpers.ts
│ └── randomName.ts
│
├── docs/ # Documentation
│ ├── ARCHITECTURE.md # This file
│ ├── design_guide.md # Design guidelines
│ ├── testing.md # Testing guide
│ └── versioning-and-migrations-user-guide.md
│
├── .projenrc.ts # Projen configuration
├── package.json # NPM package manifest
├── tsconfig.dev.json # TypeScript configuration
└── README.md # Package readme
AzapiResource uses the Template Method pattern where the base class defines the algorithm structure, and subclasses implement specific steps:
// Base class defines the algorithm
constructor(scope: Construct, id: string, props: AzapiResourceProps) {
super(scope, id);
// 1. Resolve version
this.resolvedApiVersion = this._resolveApiVersion(props.apiVersion);
// 2. Load schema
this.schema = this.apiSchema(); // Abstract method
// 3. Process properties
const processedProps = this._processProperties(props);
// 4. Validate
this.validationResult = this._validateProperties(processedProps);
// 5. Create resource
this._createAzureResource(processedProps); // Uses abstract createResourceBody()
}ApiVersionManager uses a JSII-compliant singleton to ensure a single version registry:
export class ApiVersionManager {
private static _instance: ApiVersionManager | undefined;
public static instance(): ApiVersionManager {
if (!ApiVersionManager._instance) {
ApiVersionManager._instance = new ApiVersionManager();
}
return ApiVersionManager._instance;
}
private constructor() {
// Initialize registries
}
}SchemaMapper uses a factory method for creating validated instances:
export class SchemaMapper {
public static create(schema: ApiSchema): SchemaMapper {
// Validate schema
if (!schema || !schema.resourceType) {
throw new Error("Invalid schema");
}
return new SchemaMapper(schema);
}
private constructor(schema: ApiSchema) {
// Private constructor enforces factory usage
}
}Version resolution uses different strategies based on context:
- Automatic: Use latest active version
- Pinned: Use explicitly specified version
- Constrained: Use version matching constraints
stateDiagram-v2
[*] --> Active: Release
Active --> Maintenance: Feature Complete
Maintenance --> Deprecated: Migration Available
Deprecated --> Sunset: End of Support
Sunset --> [*]: Removed
note right of Active
Full support
New features
Recommended
end note
note right of Maintenance
Bug fixes only
No new features
Still supported
end note
note right of Deprecated
Migration recommended
Limited support
Warnings shown
end note
note right of Sunset
End of life
Immediate migration
May be removed
end note
function resolveApiVersion(explicitVersion?: string, resourceType: string): string {
// 1. If version explicitly specified, validate and use it
if (explicitVersion) {
if (!validateVersionSupport(resourceType, explicitVersion)) {
throw new Error(`Unsupported version: ${explicitVersion}`);
}
return explicitVersion;
}
// 2. Try to get latest active version from registry
const latestVersion = apiVersionManager.latestVersion(resourceType);
if (latestVersion) {
return latestVersion;
}
// 3. Fall back to default version from subclass
const defaultVersion = defaultVersion();
console.warn(`Using default version: ${defaultVersion}`);
return defaultVersion;
}graph LR
A[Source Version] --> B[Collect Breaking Changes]
B --> C[Calculate Effort]
C --> D[Check Auto-Upgrade]
D --> E[Generate Warnings]
E --> F[Return Analysis]
style A fill:#e1f5ff
style F fill:#c8e6c9
sequenceDiagram
participant U as User Code
participant RC as Resource Construct
participant AR as AzapiResource
participant AVM as ApiVersionManager
participant SM as SchemaMapper
participant AP as AZAPI Provider
participant Azure as Azure API
U->>RC: new ResourceGroup(props)
RC->>RC: ensureSchemasRegistered()
RC->>AVM: registerResourceType()
RC->>AR: super(scope, id, props)
AR->>AVM: resolveApiVersion()
AVM-->>AR: resolvedVersion
AR->>AVM: versionConfig()
AVM-->>AR: schema + metadata
AR->>SM: create(schema)
SM-->>AR: schemaMapper
AR->>SM: applyDefaults(props)
SM-->>AR: propsWithDefaults
AR->>SM: validateProperties()
SM-->>AR: validationResult
alt Validation Failed
AR-->>U: throw Error
end
AR->>AVM: analyzeMigration()
AVM-->>AR: migrationAnalysis
AR->>RC: createResourceBody()
RC-->>AR: resourceBody
AR->>AP: new Resource(config)
AP->>Azure: REST API Call
Azure-->>AP: Response
AP-->>AR: terraformResource
AR->>AR: logFrameworkMessages()
AR-->>U: Resource Instance
- User Creates Resource: Instantiates L2 construct (e.g., ResourceGroup)
- Schema Registration: Ensure API versions registered with ApiVersionManager
- Version Resolution: Determine which API version to use
- Schema Loading: Load schema and version configuration
- Property Processing: Apply defaults and transformations
- Validation: Validate properties against schema
- Migration Analysis: Check for deprecations and breaking changes
- Resource Creation: Generate AZAPI Terraform resource
- Warning Display: Show deprecation warnings and migration guidance
graph TB
subgraph "E2E Tests (Few)"
A[Complete Scenarios<br/>Real Deployments]
end
subgraph "Integration Tests (Some)"
B[Terraform Apply<br/>Idempotency Check<br/>Terraform Destroy]
end
subgraph "Unit Tests (Many)"
C[Snapshot Tests<br/>Terraform Validate<br/>Terraform Plan]
end
A --> B
B --> C
style A fill:#ffcdd2
style B fill:#fff9c4
style C fill:#c8e6c9
Purpose: Fast validation without Azure deployment
Tools: Jest, CDKTF Testing Framework
Coverage:
- Snapshot testing for configuration drift detection
- Terraform validate for syntax checking
- Terraform plan for basic validation
describe("Resource Group With Defaults", () => {
it("renders correctly and matches snapshot", () => {
const stack = new TerraformStack(app, "test");
new ResourceGroup(stack, "rg", {
name: "test-rg",
location: "eastus"
});
expect(Testing.synth(stack)).toMatchSnapshot();
});
it("produces valid terraform configuration", () => {
expect(Testing.fullSynth(stack)).toBeValidTerraform();
});
});Purpose: Real deployment validation
Tools: Jest, Azure CLI authentication
Coverage:
- terraform apply → Create resources
- terraform plan → Verify idempotency
- terraform destroy → Cleanup validation
describe("Resource Group Integration", () => {
it("can be created and destroyed", () => {
const app = Testing.app();
const stack = new TerraformStack(app, "test");
new ResourceGroup(stack, "rg", {
name: `rg-test-${randomName()}`,
location: "eastus"
});
const output = app.synth();
TerraformApplyAndCheckIdempotency(output);
TerraformDestroy(output);
});
});Location: src/testing/index.ts
Provides helper functions for testing:
TerraformApply(): Deploy infrastructureTerraformPlan(): Generate execution planTerraformPlanExitCode(): Check plan statusTerraformDestroy(): Cleanup resourcesTerraformApplyAndCheckIdempotency(): Full integration testTerraformIdempotentCheck(): Verify no changes needed
The package uses JSII (JavaScript Interoperability Interface) to generate bindings for multiple languages:
graph LR
A[TypeScript Source] --> B[JSII Compiler]
B --> C[JavaScript/TypeScript]
B --> D[Python]
B --> E[Java]
B --> F[C#/.NET]
style A fill:#e1f5ff
style B fill:#fff9c4
style C fill:#c8e6c9
style D fill:#c8e6c9
style E fill:#c8e6c9
style F fill:#c8e6c9
| Language | Package | Example |
|---|---|---|
| TypeScript/JavaScript | @microsoft/terraform-cdk-constructs |
npm install @microsoft/terraform-cdk-constructs |
| Python | microsoft-cdktfconstructs |
pip install microsoft-cdktfconstructs |
| Java | com.microsoft.terraformcdkconstructs |
Maven/Gradle dependency |
| C#/.NET | Microsoft.Cdktf.Azure.TFConstructs |
dotnet add package Microsoft.Cdktf.Azure.TFConstructs |
To ensure multi-language support, the codebase follows JSII constraints:
- No function types in public APIs (use interfaces with methods)
- Use concrete types (avoid complex generics)
- Implement proper serialization for all data structures
- Explicit return types for all public methods
- Singleton patterns using instance methods
Focus on how developers think, not how Azure APIs work:
// Good: Simple, intuitive API
new ResourceGroup(this, "rg", {
name: "my-rg",
location: "eastus"
});
// Avoid: Exposing Azure API complexity
new ResourceGroup(this, "rg", {
properties: {
location: "eastus"
},
type: "Microsoft.Resources/resourceGroups@2024-11-01"
});Minimize required properties, provide secure defaults:
// Only essential properties required
const rg = new ResourceGroup(this, "rg", {
name: "my-rg",
location: "eastus"
// Optional: tags, managedBy, apiVersion, etc.
});Automatic version management with opt-in pinning:
// Automatic (recommended): Uses latest active version
new ResourceGroup(this, "rg", { name: "rg", location: "eastus" });
// Pinned (for stability): Uses specific version
new ResourceGroup(this, "rg", {
name: "rg",
location: "eastus",
apiVersion: "2024-11-01"
});Advanced features available but not required:
- Level 1: Basic resource creation with defaults
- Level 2: Custom configuration with props
- Level 3: Advanced features (RBAC, diagnostics)
- Level 4: Version management and migration
Catch errors early with detailed messages:
// Validation happens at construct time
try {
new ResourceGroup(this, "rg", {
name: "", // Invalid
location: "eastus"
});
} catch (error) {
// Error: Property validation failed for Microsoft.Resources/resourceGroups:
// - Required property 'name' is missing
}The framework is designed for easy extensibility. Adding a new service requires:
- Create service directory in
src/ - Define schemas for each API version
- Implement construct extending
AzapiResource - Register versions with
ApiVersionManager - Add tests (unit and integration)
// Example: Adding a new service
export class KeyVault extends AzapiResource {
protected defaultVersion(): string {
return "2024-01-01";
}
protected resourceType(): string {
return "Microsoft.KeyVault/vaults";
}
protected apiSchema(): ApiSchema {
return this.resolveSchema();
}
protected createResourceBody(props: any): any {
return {
location: props.location,
properties: {
sku: { name: props.sku || "standard" },
tenantId: props.tenantId
}
};
}
}When Azure releases a new API version:
- Define new schema in service schemas file
- Add version config with lifecycle metadata
- Register with ApiVersionManager
- Update tests to cover new version
- Document breaking changes if any
- Custom Validation Rules: Extend
ValidationRuleinterface - Property Transformers: Add custom transformation logic
- Migration Strategies: Define version-specific migrations
- Provider Extensions: Add new AZAPI provider features
Unlike traditional Terraform providers, this framework automatically resolves to the latest API version, keeping infrastructure current with minimal effort.
Built-in analysis of breaking changes between versions with effort estimation and automatic upgrade feasibility detection.
All validation and transformation is driven by API schemas, ensuring type safety and consistency across versions.
The AzapiResource base class provides a unified framework that handles version management, validation, and transformation transparently.
AZAPI provider classes are included in the package, eliminating the need for external provider generation tools.
The @microsoft/terraform-cdk-constructs package represents a modern approach to Azure infrastructure as code, combining:
- Direct API Access via AZAPI provider
- Intelligent Version Management with automatic resolution
- Type Safety through JSII and TypeScript
- Multi-Language Support for diverse development teams
- Comprehensive Testing ensuring production readiness
The architecture is designed for extensibility, allowing easy addition of new Azure services while maintaining backward compatibility and providing migration guidance for existing resources.
- Design Guide - Module design guidelines
- Testing Guide - Testing practices and utilities
- Versioning User Guide - API version management
- README - Package overview and quick start
- CDKTF Documentation - Terraform CDK reference
- JSII Documentation - Multi-language support
Document Version: 1.0.0
Last Updated: 2025-10-22
Maintained By: Microsoft Cloud Infrastructure Solutions Team