🔷 API Design in C# TuskLang

C# Documentation

API Design in C# TuskLang

Overview

API design is crucial for building scalable and maintainable applications. This guide covers RESTful APIs, GraphQL, gRPC, authentication, versioning, and best practices for C# TuskLang applications.

🌐 RESTful API Design

Controller Structure

[ApiController]
[Route("api/v1/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly ILogger<UsersController> _logger;
    private readonly TSKConfig _config;
    
    public UsersController(IUserService userService, ILogger<UsersController> logger, TSKConfig config)
    {
        _userService = userService;
        _logger = logger;
        _config = config;
    }
    
    [HttpGet]
    public async Task<ActionResult<PaginatedResponse<UserDto>>> GetUsers(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null)
    {
        try
        {
            var maxPageSize = _config.Get<int>("api.max_page_size", 100);
            pageSize = Math.Min(pageSize, maxPageSize);
            
            var users = await _userService.GetUsersAsync(page, pageSize, search);
            
            return Ok(new PaginatedResponse<UserDto>
            {
                Data = users.Items,
                Page = page,
                PageSize = pageSize,
                TotalCount = users.TotalCount,
                TotalPages = (int)Math.Ceiling((double)users.TotalCount / pageSize)
            });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get users");
            return StatusCode(500, new ErrorResponse("Internal server error"));
        }
    }
    
    [HttpGet("{id}")]
    public async Task<ActionResult<UserDto>> GetUser(int id)
    {
        try
        {
            var user = await _userService.GetUserByIdAsync(id);
            
            if (user == null)
            {
                return NotFound(new ErrorResponse("User not found"));
            }
            
            return Ok(user);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to get user {UserId}", id);
            return StatusCode(500, new ErrorResponse("Internal server error"));
        }
    }
    
    [HttpPost]
    public async Task<ActionResult<UserDto>> CreateUser([FromBody] CreateUserRequest request)
    {
        try
        {
            var validationResult = await ValidateCreateUserRequestAsync(request);
            if (!validationResult.IsValid)
            {
                return BadRequest(new ErrorResponse(validationResult.Errors));
            }
            
            var user = await _userService.CreateUserAsync(request);
            
            return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
        }
        catch (ValidationException ex)
        {
            return BadRequest(new ErrorResponse(ex.Message));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to create user");
            return StatusCode(500, new ErrorResponse("Internal server error"));
        }
    }
    
    [HttpPut("{id}")]
    public async Task<ActionResult<UserDto>> UpdateUser(int id, [FromBody] UpdateUserRequest request)
    {
        try
        {
            var validationResult = await ValidateUpdateUserRequestAsync(request);
            if (!validationResult.IsValid)
            {
                return BadRequest(new ErrorResponse(validationResult.Errors));
            }
            
            var user = await _userService.UpdateUserAsync(id, request);
            
            if (user == null)
            {
                return NotFound(new ErrorResponse("User not found"));
            }
            
            return Ok(user);
        }
        catch (ValidationException ex)
        {
            return BadRequest(new ErrorResponse(ex.Message));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to update user {UserId}", id);
            return StatusCode(500, new ErrorResponse("Internal server error"));
        }
    }
    
    [HttpDelete("{id}")]
    public async Task<ActionResult> DeleteUser(int id)
    {
        try
        {
            var deleted = await _userService.DeleteUserAsync(id);
            
            if (!deleted)
            {
                return NotFound(new ErrorResponse("User not found"));
            }
            
            return NoContent();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to delete user {UserId}", id);
            return StatusCode(500, new ErrorResponse("Internal server error"));
        }
    }
    
    private async Task<ValidationResult> ValidateCreateUserRequestAsync(CreateUserRequest request)
    {
        var result = new ValidationResult();
        
        if (string.IsNullOrEmpty(request.Email))
        {
            result.AddError("Email is required");
        }
        else if (!IsValidEmail(request.Email))
        {
            result.AddError("Invalid email format");
        }
        
        if (string.IsNullOrEmpty(request.Password))
        {
            result.AddError("Password is required");
        }
        else if (request.Password.Length < 8)
        {
            result.AddError("Password must be at least 8 characters long");
        }
        
        return result;
    }
    
    private async Task<ValidationResult> ValidateUpdateUserRequestAsync(UpdateUserRequest request)
    {
        var result = new ValidationResult();
        
        if (!string.IsNullOrEmpty(request.Email) && !IsValidEmail(request.Email))
        {
            result.AddError("Invalid email format");
        }
        
        return result;
    }
    
    private bool IsValidEmail(string email)
    {
        try
        {
            var addr = new System.Net.Mail.MailAddress(email);
            return addr.Address == email;
        }
        catch
        {
            return false;
        }
    }
}

Response Models

public class PaginatedResponse<T>
{
    public List<T> Data { get; set; } = new();
    public int Page { get; set; }
    public int PageSize { get; set; }
    public int TotalCount { get; set; }
    public int TotalPages { get; set; }
    public bool HasNextPage => Page < TotalPages;
    public bool HasPreviousPage => Page > 1;
}

public class ErrorResponse { public string Message { get; set; } public List<string> Errors { get; set; } = new(); public string? TraceId { get; set; } public ErrorResponse(string message) { Message = message; } public ErrorResponse(List<string> errors) { Message = "Validation failed"; Errors = errors; } }

public class UserDto { public int Id { get; set; } public string Email { get; set; } = string.Empty; public string FirstName { get; set; } = string.Empty; public string LastName { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } }

public class CreateUserRequest { public string Email { get; set; } = string.Empty; public string Password { get; set; } = string.Empty; public string FirstName { get; set; } = string.Empty; public string LastName { get; set; } = string.Empty; }

public class UpdateUserRequest { public string? Email { get; set; } public string? FirstName { get; set; } public string? LastName { get; set; } }

Service Layer

public interface IUserService
{
    Task<PaginatedResult<UserDto>> GetUsersAsync(int page, int pageSize, string? search);
    Task<UserDto?> GetUserByIdAsync(int id);
    Task<UserDto> CreateUserAsync(CreateUserRequest request);
    Task<UserDto?> UpdateUserAsync(int id, UpdateUserRequest request);
    Task<bool> DeleteUserAsync(int id);
}

public class UserService : IUserService { private readonly IDbConnection _connection; private readonly ILogger<UserService> _logger; private readonly TSKConfig _config; private readonly IPasswordHasher _passwordHasher; public UserService(IDbConnection connection, ILogger<UserService> logger, TSKConfig config, IPasswordHasher passwordHasher) { _connection = connection; _logger = logger; _config = config; _passwordHasher = passwordHasher; } public async Task<PaginatedResult<UserDto>> GetUsersAsync(int page, int pageSize, string? search) { var offset = (page - 1) * pageSize; var whereClause = ""; var parameters = new DynamicParameters(); if (!string.IsNullOrEmpty(search)) { whereClause = "WHERE email ILIKE @Search OR first_name ILIKE @Search OR last_name ILIKE @Search"; parameters.Add("@Search", $"%{search}%"); } var countQuery = $@" SELECT COUNT(*) FROM users {whereClause}"; var totalCount = await _connection.ExecuteScalarAsync<int>(countQuery, parameters); var query = $@" SELECT id, email, first_name, last_name, created_at, updated_at FROM users {whereClause} ORDER BY created_at DESC LIMIT @PageSize OFFSET @Offset"; parameters.Add("@PageSize", pageSize); parameters.Add("@Offset", offset); var users = await _connection.QueryAsync<UserDto>(query, parameters); return new PaginatedResult<UserDto> { Items = users.ToList(), TotalCount = totalCount }; } public async Task<UserDto?> GetUserByIdAsync(int id) { var query = @" SELECT id, email, first_name, last_name, created_at, updated_at FROM users WHERE id = @Id"; var parameters = new { Id = id }; return await _connection.QueryFirstOrDefaultAsync<UserDto>(query, parameters); } public async Task<UserDto> CreateUserAsync(CreateUserRequest request) { // Check if user already exists var existingUser = await GetUserByEmailAsync(request.Email); if (existingUser != null) { throw new ValidationException("User with this email already exists"); } // Hash password var hashedPassword = _passwordHasher.HashPassword(request.Password); var query = @" INSERT INTO users (email, password_hash, first_name, last_name, created_at, updated_at) VALUES (@Email, @PasswordHash, @FirstName, @LastName, @CreatedAt, @UpdatedAt) RETURNING id, email, first_name, last_name, created_at, updated_at"; var parameters = new { request.Email, PasswordHash = hashedPassword, request.FirstName, request.LastName, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow }; return await _connection.QueryFirstAsync<UserDto>(query, parameters); } public async Task<UserDto?> UpdateUserAsync(int id, UpdateUserRequest request) { var existingUser = await GetUserByIdAsync(id); if (existingUser == null) { return null; } var updateFields = new List<string>(); var parameters = new DynamicParameters(); parameters.Add("@Id", id); if (!string.IsNullOrEmpty(request.Email)) { updateFields.Add("email = @Email"); parameters.Add("@Email", request.Email); } if (!string.IsNullOrEmpty(request.FirstName)) { updateFields.Add("first_name = @FirstName"); parameters.Add("@FirstName", request.FirstName); } if (!string.IsNullOrEmpty(request.LastName)) { updateFields.Add("last_name = @LastName"); parameters.Add("@LastName", request.LastName); } if (!updateFields.Any()) { return existingUser; } updateFields.Add("updated_at = @UpdatedAt"); parameters.Add("@UpdatedAt", DateTime.UtcNow); var query = $@" UPDATE users SET {string.Join(", ", updateFields)} WHERE id = @Id RETURNING id, email, first_name, last_name, created_at, updated_at"; return await _connection.QueryFirstOrDefaultAsync<UserDto>(query, parameters); } public async Task<bool> DeleteUserAsync(int id) { var query = "DELETE FROM users WHERE id = @Id"; var parameters = new { Id = id }; var rowsAffected = await _connection.ExecuteAsync(query, parameters); return rowsAffected > 0; } private async Task<UserDto?> GetUserByEmailAsync(string email) { var query = @" SELECT id, email, first_name, last_name, created_at, updated_at FROM users WHERE email = @Email"; var parameters = new { Email = email }; return await _connection.QueryFirstOrDefaultAsync<UserDto>(query, parameters); } }

public class PaginatedResult<T> { public List<T> Items { get; set; } = new(); public int TotalCount { get; set; } }

🔐 Authentication & Authorization

JWT Authentication

public class JwtAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    private readonly TSKConfig _config;
    private readonly IUserService _userService;
    
    public JwtAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder,
        ISystemClock clock,
        TSKConfig config,
        IUserService userService)
        : base(options, logger, encoder, clock)
    {
        _config = config;
        _userService = userService;
    }
    
    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.ContainsKey("Authorization"))
        {
            return AuthenticateResult.Fail("Authorization header not found");
        }
        
        var authHeader = Request.Headers["Authorization"].ToString();
        if (!authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
        {
            return AuthenticateResult.Fail("Bearer token not found");
        }
        
        var token = authHeader.Substring("Bearer ".Length).Trim();
        
        try
        {
            var principal = ValidateToken(token);
            var ticket = new AuthenticationTicket(principal, Scheme.Name);
            
            return AuthenticateResult.Success(ticket);
        }
        catch (Exception ex)
        {
            return AuthenticateResult.Fail($"Token validation failed: {ex.Message}");
        }
    }
    
    private ClaimsPrincipal ValidateToken(string token)
    {
        var jwtSecret = _config.Get<string>("security.jwt_secret");
        if (string.IsNullOrEmpty(jwtSecret))
        {
            throw new InvalidOperationException("JWT secret not configured");
        }
        
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(jwtSecret);
        
        tokenHandler.ValidateToken(token, new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false,
            ClockSkew = TimeSpan.Zero
        }, out SecurityToken validatedToken);
        
        var jwtToken = (JwtSecurityToken)validatedToken;
        var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "user_id").Value);
        
        var claims = new[]
        {
            new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
            new Claim(ClaimTypes.Name, jwtToken.Claims.First(x => x.Type == "email").Value),
            new Claim(ClaimTypes.Role, jwtToken.Claims.First(x => x.Type == "role").Value)
        };
        
        var identity = new ClaimsIdentity(claims, Scheme.Name);
        return new ClaimsPrincipal(identity);
    }
}

public class JwtTokenService { private readonly TSKConfig _config; private readonly IUserService _userService; public JwtTokenService(TSKConfig config, IUserService userService) { _config = config; _userService = userService; } public async Task<string> GenerateTokenAsync(int userId) { var user = await _userService.GetUserByIdAsync(userId); if (user == null) { throw new ArgumentException("User not found"); } var jwtSecret = _config.Get<string>("security.jwt_secret"); var tokenExpiration = _config.Get<int>("security.token_expiration_minutes", 60); var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(jwtSecret); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim("user_id", userId.ToString()), new Claim("email", user.Email), new Claim("role", "user") }), Expires = DateTime.UtcNow.AddMinutes(tokenExpiration), SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } }

Role-Based Authorization

[Authorize(Roles = "Admin")]
[ApiController]
[Route("api/v1/[controller]")]
public class AdminController : ControllerBase
{
    private readonly ILogger<AdminController> _logger;
    private readonly TSKConfig _config;
    
    public AdminController(ILogger<AdminController> logger, TSKConfig config)
    {
        _logger = logger;
        _config = config;
    }
    
    [HttpGet("system-info")]
    public ActionResult<SystemInfoDto> GetSystemInfo()
    {
        var systemInfo = new SystemInfoDto
        {
            Version = _config.Get<string>("app.version", "1.0.0"),
            Environment = _config.Get<string>("app.environment", "development"),
            DatabaseConnection = _config.Get<string>("database.connection_string", ""),
            ApiBaseUrl = _config.Get<string>("api.base_url", ""),
            Timestamp = DateTime.UtcNow
        };
        
        return Ok(systemInfo);
    }
    
    [HttpPost("config-reload")]
    public async Task<ActionResult> ReloadConfiguration()
    {
        try
        {
            // Implementation depends on your configuration reload mechanism
            await Task.Delay(100); // Simulate reload
            
            _logger.LogInformation("Configuration reloaded by admin");
            return Ok(new { message = "Configuration reloaded successfully" });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to reload configuration");
            return StatusCode(500, new ErrorResponse("Failed to reload configuration"));
        }
    }
}

public class SystemInfoDto { public string Version { get; set; } = string.Empty; public string Environment { get; set; } = string.Empty; public string DatabaseConnection { get; set; } = string.Empty; public string ApiBaseUrl { get; set; } = string.Empty; public DateTime Timestamp { get; set; } }

🔄 API Versioning

Versioning Strategies

[ApiController]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;
    private readonly ILogger<UsersController> _logger;
    
    public UsersController(IUserService userService, ILogger<UsersController> logger)
    {
        _userService = userService;
        _logger = logger;
    }
    
    [HttpGet]
    [MapToApiVersion("1.0")]
    public async Task<ActionResult<List<UserDto>>> GetUsersV1()
    {
        // Version 1.0 implementation
        var users = await _userService.GetUsersAsync(1, 100, null);
        return Ok(users.Items);
    }
    
    [HttpGet]
    [MapToApiVersion("2.0")]
    public async Task<ActionResult<PaginatedResponse<UserDto>>> GetUsersV2(
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20,
        [FromQuery] string? search = null)
    {
        // Version 2.0 implementation with pagination
        var users = await _userService.GetUsersAsync(page, pageSize, search);
        
        return Ok(new PaginatedResponse<UserDto>
        {
            Data = users.Items,
            Page = page,
            PageSize = pageSize,
            TotalCount = users.TotalCount,
            TotalPages = (int)Math.Ceiling((double)users.TotalCount / pageSize)
        });
    }
    
    [HttpGet("{id}")]
    [MapToApiVersion("1.0")]
    public async Task<ActionResult<UserDto>> GetUserV1(int id)
    {
        var user = await _userService.GetUserByIdAsync(id);
        
        if (user == null)
        {
            return NotFound();
        }
        
        return Ok(user);
    }
    
    [HttpGet("{id}")]
    [MapToApiVersion("2.0")]
    public async Task<ActionResult<UserDetailDto>> GetUserV2(int id)
    {
        var user = await _userService.GetUserByIdAsync(id);
        
        if (user == null)
        {
            return NotFound(new ErrorResponse("User not found"));
        }
        
        var userDetail = new UserDetailDto
        {
            Id = user.Id,
            Email = user.Email,
            FirstName = user.FirstName,
            LastName = user.LastName,
            FullName = $"{user.FirstName} {user.LastName}",
            CreatedAt = user.CreatedAt,
            UpdatedAt = user.UpdatedAt
        };
        
        return Ok(userDetail);
    }
}

public class UserDetailDto { public int Id { get; set; } public string Email { get; set; } = string.Empty; public string FirstName { get; set; } = string.Empty; public string LastName { get; set; } = string.Empty; public string FullName { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } public DateTime UpdatedAt { get; set; } }

📊 API Documentation

Swagger/OpenAPI Configuration

public class SwaggerConfiguration
{
    public static void ConfigureSwagger(IServiceCollection services, TSKConfig config)
    {
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Title = config.Get<string>("api.title", "My API"),
                Version = "v1",
                Description = config.Get<string>("api.description", "API Documentation"),
                Contact = new OpenApiContact
                {
                    Name = config.Get<string>("api.contact.name", "API Support"),
                    Email = config.Get<string>("api.contact.email", "support@example.com")
                }
            });
            
            c.SwaggerDoc("v2", new OpenApiInfo
            {
                Title = config.Get<string>("api.title", "My API"),
                Version = "v2",
                Description = config.Get<string>("api.description", "API Documentation v2"),
                Contact = new OpenApiContact
                {
                    Name = config.Get<string>("api.contact.name", "API Support"),
                    Email = config.Get<string>("api.contact.email", "support@example.com")
                }
            });
            
            // Add JWT authentication
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey,
                Scheme = "Bearer"
            });
            
            c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                    },
                    Array.Empty<string>()
                }
            });
            
            // Include XML comments
            var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
            var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
            if (File.Exists(xmlPath))
            {
                c.IncludeXmlComments(xmlPath);
            }
        });
    }
}

🚀 Performance Optimization

Caching Strategies

public class CachedUserService : IUserService
{
    private readonly IUserService _userService;
    private readonly IDistributedCache _cache;
    private readonly ILogger<CachedUserService> _logger;
    private readonly TSKConfig _config;
    
    public CachedUserService(IUserService userService, IDistributedCache cache, 
        ILogger<CachedUserService> logger, TSKConfig config)
    {
        _userService = userService;
        _cache = cache;
        _logger = logger;
        _config = config;
    }
    
    public async Task<PaginatedResult<UserDto>> GetUsersAsync(int page, int pageSize, string? search)
    {
        var cacheKey = $"users:page:{page}:size:{pageSize}:search:{search ?? "null"}";
        var cacheExpiration = _config.Get<int>("cache.user_list_expiration_minutes", 5);
        
        var cachedResult = await _cache.GetStringAsync(cacheKey);
        if (!string.IsNullOrEmpty(cachedResult))
        {
            return JsonSerializer.Deserialize<PaginatedResult<UserDto>>(cachedResult)!;
        }
        
        var result = await _userService.GetUsersAsync(page, pageSize, search);
        
        var cacheOptions = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheExpiration)
        };
        
        await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(result), cacheOptions);
        
        return result;
    }
    
    public async Task<UserDto?> GetUserByIdAsync(int id)
    {
        var cacheKey = $"user:{id}";
        var cacheExpiration = _config.Get<int>("cache.user_expiration_minutes", 10);
        
        var cachedUser = await _cache.GetStringAsync(cacheKey);
        if (!string.IsNullOrEmpty(cachedUser))
        {
            return JsonSerializer.Deserialize<UserDto>(cachedUser);
        }
        
        var user = await _userService.GetUserByIdAsync(id);
        
        if (user != null)
        {
            var cacheOptions = new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(cacheExpiration)
            };
            
            await _cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(user), cacheOptions);
        }
        
        return user;
    }
    
    public async Task<UserDto> CreateUserAsync(CreateUserRequest request)
    {
        var user = await _userService.CreateUserAsync(request);
        
        // Invalidate user list cache
        await InvalidateUserListCacheAsync();
        
        return user;
    }
    
    public async Task<UserDto?> UpdateUserAsync(int id, UpdateUserRequest request)
    {
        var user = await _userService.UpdateUserAsync(id, request);
        
        if (user != null)
        {
            // Invalidate specific user cache
            await _cache.RemoveAsync($"user:{id}");
            
            // Invalidate user list cache
            await InvalidateUserListCacheAsync();
        }
        
        return user;
    }
    
    public async Task<bool> DeleteUserAsync(int id)
    {
        var deleted = await _userService.DeleteUserAsync(id);
        
        if (deleted)
        {
            // Invalidate specific user cache
            await _cache.RemoveAsync($"user:{id}");
            
            // Invalidate user list cache
            await InvalidateUserListCacheAsync();
        }
        
        return deleted;
    }
    
    private async Task InvalidateUserListCacheAsync()
    {
        // This is a simplified implementation
        // In a real application, you might use cache tags or patterns
        var keys = new[] { "users:page:1:size:20:search:null", "users:page:1:size:50:search:null" };
        
        foreach (var key in keys)
        {
            await _cache.RemoveAsync(key);
        }
    }
}

📝 Summary

This guide covered comprehensive API design patterns for C# TuskLang applications:

- RESTful API Design: Controller structure, response models, and service layer implementation - Authentication & Authorization: JWT authentication and role-based authorization - API Versioning: Multiple versioning strategies with backward compatibility - API Documentation: Swagger/OpenAPI configuration with comprehensive documentation - Performance Optimization: Caching strategies for improved API performance

These patterns ensure your C# TuskLang APIs are scalable, secure, well-documented, and performant.