Production-ready code patterns and shortcuts for common use cases using Noundry libraries
You're viewing the free version of Noundry Blueprints. Paid subscribers get access to:
Attribute-based authorization with policies and claims
using Noundry.Guardian;
// Add Guardian with custom policies
builder.Services.AddGuardian(options =>
{
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("Admin"));
options.AddPolicy("CanEditPosts", policy =>
policy.RequireClaim("Permission", "Posts.Edit"));
options.AddPolicy("MinimumAge", policy =>
policy.RequireAssertion(context =>
{
var ageClaim = context.User.FindFirst("age");
return ageClaim != null && int.Parse(ageClaim.Value) >= 18;
}));
});
// Use in controllers
[Authorize(Policy = "AdminOnly")]
public class AdminController : Controller
{
[HttpPost]
[Authorize(Policy = "CanEditPosts")]
public async Task EditPost(int id, Post model)
{
// Only users with "Posts.Edit" claim can access
return Ok();
}
}
Defensive programming with guard clauses
using Guardian;
public class Product
{
public string Name { get; }
public decimal Price { get; }
public int StockQuantity { get; }
public Product(string name, decimal price, int stockQuantity)
{
Name = Guard.Against.NullOrWhiteSpace(name);
Price = Guard.Against.NegativeOrZero(price);
StockQuantity = Guard.Against.Negative(stockQuantity);
}
}
public class OrderService
{
public async Task ProcessOrder(Order order, User user)
{
Guard.Against.Default(order.Id);
Guard.Against.InvalidFormat(user.Email, @"^[^@\s]+@[^@\s]+\.[^@\s]+$");
Guard.Against.OutOfRange(order.Total, 0.01m, 10000m);
await SaveOrderAsync(order);
}
}
Readable test assertions with method chaining
using Noundry.Assertive;
using Xunit;
public class UserTests
{
[Fact]
public void TestUserCreation()
{
var user = new User { Name = "John Doe", Age = 30, Email = "john@example.com" };
user.Assert()
.IsNotNull()
.Satisfies(u => u.Age >= 18, "User must be an adult")
.Satisfies(u => !string.IsNullOrEmpty(u.Name), "User must have a name");
}
[Fact]
public void TestCollectionOperations()
{
var numbers = new List { 1, 2, 3, 4, 5 };
numbers.Assert()
.IsNotEmpty()
.HasCount(5)
.Contains(3)
.DoesNotContain(10);
}
[Fact]
public void TestNumericAssertions()
{
42.Assert()
.IsNotNull()
.IsEqualTo(42)
.IsOfType()
.IsInRange(1, 100)
.Satisfies(x => x > 0, "Number should be positive");
}
}
Zod-inspired fluent validation for .NET
using Noundry.Sod;
// Define reusable schema
var userSchema = Sod.Object()
.Field(u => u.Email,
Sod.String().Email().Required())
.Field(u => u.Age,
Sod.Number().Min(18).Max(120))
.Field(u => u.Username,
Sod.String().Min(3).Max(20).Regex("^[a-zA-Z0-9_]+$"))
.Field(u => u.Password,
Sod.String().Min(8).Regex(@"^(?=.*[A-Z])(?=.*\d).*$"))
.Field(u => u.Website,
Sod.String().Url().Optional());
// Use in API controller
[HttpPost("register")]
public async Task Register(User user)
{
var result = userSchema.Parse(user);
if (!result.Success)
{
return BadRequest(result.Errors);
}
var validUser = result.Data;
await _userService.CreateAsync(validUser);
return Ok(new { message = "User created successfully" });
}
Secure environment variables with encryption
using Noundry.DotEnvX.Core.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Load .env with encryption & validation
builder.Configuration.AddDotEnvX(options =>
{
options.Path = new[] { ".env", ".env.production" };
options.EnvironmentSpecific = true;
options.Required = new[]
{
"DATABASE_URL",
"JWT_SECRET",
"STRIPE_API_KEY"
};
options.EncryptionKey = Environment.GetEnvironmentVariable("DOTENVX_KEY");
});
// Use encrypted configuration
var jwtSecret = builder.Configuration["JWT_SECRET"]; // Automatically decrypted
var dbUrl = builder.Configuration["DATABASE_URL"];
// .env file example (values are encrypted):
// DATABASE_URL=postgresql://localhost/mydb
// JWT_SECRET="encrypted:BDb7t3QkTRp2..."
// STRIPE_API_KEY="encrypted:AES256:base64value"
Manage encrypted secrets from the command line
# Install CLI tool
dotnet tool install --global Noundry.DotEnvX.Tool
# Generate encryption keypair
dotenvx keypair --save
# Set encrypted value
dotenvx set API_SECRET=supersecret --encrypt
# Set multiple values
dotenvx set API_KEY=key123 DEBUG=true PORT=3000
# List variables (masks sensitive values)
dotenvx list
# Get specific value
dotenvx get DATABASE_URL
# Encrypt all existing values
dotenvx encrypt
# Decrypt for viewing (doesn't save)
dotenvx decrypt
# Run command with env loaded
dotenvx run -- dotnet run
Type-safe HTTP clients with Refit
using Refit;
using Noundry.Connector.Extensions;
// Define your API interface
public interface IJsonPlaceholderApi
{
[Get("/users")]
Task> GetUsersAsync(CancellationToken cancellationToken = default);
[Get("/users/{id}")]
Task GetUserAsync(int id, CancellationToken cancellationToken = default);
[Post("/users")]
Task CreateUserAsync([Body] User user, CancellationToken cancellationToken = default);
}
// Configure in DI
builder.Services.AddConnector(options =>
{
options.BaseUrl = "https://jsonplaceholder.typicode.com";
options.DefaultHeaders["User-Agent"] = "MyApp/1.0.0";
}, new TokenAuthenticationProvider("your-api-token"));
// Use in your service
public class UserService
{
private readonly IJsonPlaceholderApi _api;
public async Task> GetUsersByCityAsync(string city)
{
var users = await _api.GetUsersAsync();
return users.Where(u => u.Address.City.Contains(city, StringComparison.OrdinalIgnoreCase));
}
}
Full Create, Read, Update, Delete with type-safety
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IJsonPlaceholderApi _api;
public UsersController(IJsonPlaceholderApi api) => _api = api;
// GET: api/users
[HttpGet]
public async Task>> GetUsers()
{
var users = await _api.GetUsersAsync();
return Ok(users);
}
// GET: api/users/{id}
[HttpGet("{id}")]
public async Task> GetUser(int id)
{
var user = await _api.GetUserAsync(id);
return Ok(user);
}
// POST: api/users
[HttpPost]
public async Task> CreateUser(User user)
{
var created = await _api.CreateUserAsync(user);
return CreatedAtAction(nameof(GetUser), new { id = created.Id }, created);
}
// PUT: api/users/{id}
[HttpPut("{id}")]
public async Task> UpdateUser(int id, User user)
{
var updated = await _api.UpdateUserAsync(id, user);
return Ok(updated);
}
// DELETE: api/users/{id}
[HttpDelete("{id}")]
public async Task DeleteUser(int id)
{
await _api.DeleteUserAsync(id);
return NoContent();
}
}
GitHub API integration with OAuth
using Noundry.Connector.Extensions;
// Configure OAuth 2.0 for GitHub
builder.Services.AddOAuthAuthentication(config =>
{
config.ClientId = builder.Configuration["GitHub:ClientId"];
config.ClientSecret = builder.Configuration["GitHub:ClientSecret"];
config.TokenEndpoint = "https://github.com/login/oauth/access_token";
config.AuthorizationEndpoint = "https://github.com/login/oauth/authorize";
config.Scope = "repo user:email";
config.GrantType = "authorization_code";
});
// Configure GitHub API client
builder.Services.AddConnector(options =>
{
options.BaseUrl = "https://api.github.com";
options.DefaultHeaders["Accept"] = "application/vnd.github.v3+json";
options.DefaultHeaders["User-Agent"] = "MyGitHubApp/1.0.0";
});
// Use in service
public class GitHubService
{
private readonly IGitHubApi _gitHubApi;
public async Task> GetMyRepositoriesAsync()
{
var repos = await _gitHubApi.GetUserRepositoriesAsync("owner");
// Use LINQ to analyze
return repos
.Where(r => r.Stars > 0)
.OrderByDescending(r => r.Stars)
.Take(10);
}
}
LINQ-style database queries with type-safety
using Noundry.Tuxedo;
public class ProductRepository
{
private readonly IDbContext _db;
// Basic queries
public async Task> GetActiveProducts()
{
return await _db.Query()
.Where(p => p.IsActive == true)
.Where(p => p.Stock > 0)
.OrderBy(p => p.Name)
.ToListAsync();
}
// Pagination
public async Task> GetPagedProducts(int page, int size)
{
return await _db.Query()
.OrderBy(p => p.Name)
.Skip((page - 1) * size)
.Take(size)
.ToListAsync();
}
// Insert/Update
public async Task CreateAsync(Product product)
{
return await _db.InsertAsync(product);
}
public async Task UpdatePriceAsync(int id, decimal newPrice)
{
await _db.Update()
.Set(p => p.Price, newPrice)
.Set(p => p.UpdatedAt, DateTime.UtcNow)
.Where(p => p.Id == id)
.ExecuteAsync();
}
// Aggregations
public async Task GetAveragePriceAsync()
{
return await _db.Query()
.Where(p => p.IsActive)
.AverageAsync(p => p.Price);
}
}
Type-safe joins with grouping and aggregations
using Noundry.Tuxedo;
public class OrderRepository
{
private readonly IDbContext _db;
// Join with projection
public async Task> GetProductsWithCategories()
{
return await _db.Query()
.Join((p, c) => p.CategoryId == c.Id)
.Select((p, c) => new ProductWithCategory
{
ProductName = p.Name,
CategoryName = c.Name,
Price = p.Price,
InStock = p.Stock > 0
})
.ToListAsync();
}
// Multiple joins
public async Task> GetOrderDetailsAsync()
{
return await _db.Query()
.Join((o, c) => o.CustomerId == c.Id)
.Join((o, c, p) => o.ProductId == p.Id)
.Select((o, c, p) => new OrderDetails
{
OrderId = o.Id,
CustomerName = c.Name,
ProductName = p.Name,
TotalAmount = o.Quantity * p.Price
})
.ToListAsync();
}
// Group by with aggregations
public async Task> GetCategoryStatsAsync()
{
return await _db.Query()
.GroupBy(p => p.CategoryId)
.Select(g => new CategoryStats
{
CategoryId = g.Key,
ProductCount = g.Count(),
TotalValue = g.Sum(p => p.Price * p.Stock),
AveragePrice = g.Average(p => p.Price)
})
.ToListAsync();
}
// Transactions
public async Task TransferStock(int fromId, int toId, int quantity)
{
using var transaction = await _db.BeginTransactionAsync();
try
{
await _db.Update()
.Set(p => p.Stock, p => p.Stock - quantity)
.Where(p => p.Id == fromId)
.ExecuteAsync();
await _db.Update()
.Set(p => p.Stock, p => p.Stock + quantity)
.Where(p => p.Id == toId)
.ExecuteAsync();
await transaction.CommitAsync();
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
}
Fast CSV to database with schema inference
using Noundry.Slurp;
// As a Library
public class DataImporter
{
private readonly ISlurpService _slurp;
public async Task ImportCustomers(Stream csvStream)
{
var result = await _slurp.IngestCsvAsync(csvStream, options =>
{
options.TableName = "customers";
options.Provider = DatabaseProvider.PostgreSQL;
options.ConnectionString = _config["DATABASE_URL"];
options.BatchSize = 5000;
options.CreateTableIfNotExists = true;
// Column mapping
options.ColumnMappings = new Dictionary
{
["First Name"] = "first_name",
["Last Name"] = "last_name",
["E-mail"] = "email"
};
// Transform data
options.Transform = (row) =>
{
row["email"] = row["email"].ToLower();
row["created_at"] = DateTime.UtcNow;
return row;
};
});
Console.WriteLine($"Imported {result.RowsProcessed} rows in {result.Duration}");
}
}
// As CLI Tool
# Install
dotnet tool install --global Noundry.Slurp.Tool
# Import CSV
slurp customers.csv --provider postgres --connection $DB_URL --table customers
# Output:
✓ Analyzing CSV structure...
✓ Detected schema: 5 columns, 10,000 rows
⚡ Ingesting at 125,000 rows/sec
✅ Completed: 10,000 rows in 0.08 seconds
AI-powered Noundry code generation
# Install Andy CLI
dotnet tool install -g Noundry.Andy
# Authenticate
andy auth login
# Generate Noundry.UI form
andy generate "form UI using Noundry.UI with fields: name, email, phone"
# Generate API endpoint
andy generate "CRUD API for Product entity with Guardian authorization"
# Generate Drizzle schema
andy generate "database schema for e-commerce with users, products, orders"
# Start interactive chat
andy chat
# Example output:
✅ Generated ProductForm.razor
✅ Generated ProductController.cs
✅ Generated IProductService.cs
✅ Applied Guardian authorization policies
✓ Code generation complete!
# Features:
- Uses CodeLlama-7B for generation
- Template-based with Noundry patterns
- Generates TagHelpers, Services, Controllers
- Local execution for security
- Real-time streaming responses
Initialize Bun + Hono + Drizzle project
# Install and run ndts CLI
bunx @noundryfx/ndts-cli init
# Or with defaults (fast!)
bunx @noundryfx/ndts-cli init -y
# Interactive wizard prompts:
? Project name: my-app
? Select API architecture pattern:
❯ Direct API (DAPI) - Own database, cache, queues
Backend for Frontend (BFF) - Wrap existing backend
# If DAPI:
? Select database: SQLite / PostgreSQL / MySQL
? Select email provider: Resend / SendGrid / SMTP / None
? Include caching? Y/n
? Include queues? Y/n
? Include blob storage? Y/n
# Generated structure:
my-app/
├── packages/
│ ├── server/ # Hono API (TypeScript)
│ │ ├── src/
│ │ │ ├── routes/ # API endpoints
│ │ │ ├── schema/ # Drizzle ORM schema
│ │ │ ├── middleware/ # Auth, logging
│ │ │ └── config/ # Database, cache
│ │ └── package.json
│ └── client/ # Pure HTML + TS (NO React!)
│ ├── pages/ # HTML files
│ ├── src/ # TypeScript modules
│ └── package.json
# Start development
cd my-app
bun install
bun run dev
# Server: http://localhost:3001
# Client: http://localhost:3000
Direct database access with Drizzle ORM
import { Hono } from 'hono';
import { db } from '../config/database';
import { users } from '../schema/users';
import { eq } from 'drizzle-orm';
import { auth } from '../middleware/auth';
const userRoutes = new Hono();
// Protect all routes
userRoutes.use('*', auth);
// GET /api/users - List all users
userRoutes.get('/', async (c) => {
const allUsers = await db.select().from(users);
return c.json(allUsers);
});
// GET /api/users/:id - Get single user
userRoutes.get('/:id', async (c) => {
const id = parseInt(c.req.param('id'));
const user = await db.select()
.from(users)
.where(eq(users.id, id))
.get();
if (!user) {
return c.json({ error: 'User not found' }, 404);
}
return c.json(user);
});
// POST /api/users - Create user
userRoutes.post('/', async (c) => {
const body = await c.req.json();
const newUser = await db.insert(users)
.values({
name: body.name,
email: body.email,
createdAt: new Date()
})
.returning()
.get();
return c.json(newUser, 201);
});
// PUT /api/users/:id - Update user
userRoutes.put('/:id', async (c) => {
const id = parseInt(c.req.param('id'));
const body = await c.req.json();
const updated = await db.update(users)
.set({
name: body.name,
email: body.email,
updatedAt: new Date()
})
.where(eq(users.id, id))
.returning()
.get();
return c.json(updated);
});
// DELETE /api/users/:id
userRoutes.delete('/:id', async (c) => {
const id = parseInt(c.req.param('id'));
await db.delete(users)
.where(eq(users.id, id));
return c.json({ message: 'User deleted' });
});
export default userRoutes;
Wrap and enhance existing backend APIs
import { BaseService } from './BaseService.js';
import type { Context } from 'hono';
interface User {
id: number;
name: string;
email: string;
}
export class UserService extends BaseService {
// Call real backend, transform for frontend
async getUsers(token?: string, c?: Context) {
// Forward request to real backend (.NET, Java, Python, etc.)
const users = await this.fetchFromBackend(
'/api/users',
token,
{ method: 'GET' }
);
// Transform data for frontend UI
return users.map(user => ({
...user,
displayName: user.name,
initials: this.generateInitials(user.name),
avatarColor: this.generateAvatarColor(user.id)
}));
}
// Aggregate multiple backend calls
async getUserDashboard(userId: number, token?: string) {
const [user, stats, activity] = await Promise.all([
this.fetchFromBackend(`/api/users/${userId}`, token),
this.fetchFromBackend(`/api/users/${userId}/stats`, token),
this.fetchFromBackend(`/api/users/${userId}/activity`, token)
]);
// Combine and transform
return {
user,
stats,
recentActivity: activity.slice(0, 10),
hasActivity: activity.length > 0
};
}
// Helper methods
private generateInitials(name: string): string {
return name.split(' ')
.map(n => n[0])
.join('')
.toUpperCase()
.slice(0, 2);
}
private generateAvatarColor(id: number): string {
const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'];
return colors[id % colors.length];
}
}
// Use in routes (packages/server/src/routes/users.ts)
import { Hono } from 'hono';
import { UserService } from '../services/UserService.js';
import { auth } from '../middleware/auth.js';
const app = new Hono();
const userService = new UserService(Bun.env.BACKEND_API_URL!);
app.use('*', auth);
app.get('/', async (c) => {
const token = c.get('token');
const users = await userService.getUsers(token, c);
return c.json(users);
});
export default app;
Secure authentication with JWT tokens
import { Context, Next } from 'hono';
import { verify } from 'hono/jwt';
export async function auth(c: Context, next: Next) {
const authHeader = c.req.header('Authorization');
if (!authHeader?.startsWith('Bearer ')) {
return c.json({ error: 'Unauthorized' }, 401);
}
const token = authHeader.substring(7);
try {
const payload = await verify(token, Bun.env.JWT_SECRET!);
c.set('userId', payload.userId);
c.set('token', token); // For BFF forwarding
await next();
} catch (error) {
return c.json({ error: 'Invalid token' }, 401);
}
}
// Login route (packages/server/src/routes/auth.ts)
import { Hono } from 'hono';
import { sign } from 'hono/jwt';
import bcrypt from 'bcryptjs';
const authRoutes = new Hono();
authRoutes.post('/login', async (c) => {
const { email, password } = await c.req.json();
// Verify credentials (from database or backend API)
const user = await findUserByEmail(email);
if (!user || !await bcrypt.compare(password, user.password)) {
return c.json({ error: 'Invalid credentials' }, 401);
}
// Generate JWT
const token = await sign(
{ userId: user.id, email: user.email },
Bun.env.JWT_SECRET!
);
return c.json({
token,
user: {
id: user.id,
name: user.name,
email: user.email
}
});
});
authRoutes.post('/register', async (c) => {
const { email, password, name } = await c.req.json();
// Hash password
const hashedPassword = await bcrypt.hash(password, 10);
// Create user
const user = await createUser({ email, password: hashedPassword, name });
// Generate token
const token = await sign(
{ userId: user.id, email: user.email },
Bun.env.JWT_SECRET!
);
return c.json({ token, user }, 201);
});
export default authRoutes;
Modern TypeScript ORM with full type-safety
import { pgTable, serial, varchar, decimal, integer, timestamp } from 'drizzle-orm/pg-core';
import { eq, and, gte, lte, desc } from 'drizzle-orm';
// Define schema
export const products = pgTable('products', {
id: serial('id').primaryKey(),
name: varchar('name', { length: 255 }).notNull(),
description: varchar('description', { length: 1000 }),
price: decimal('price', { precision: 10, scale: 2 }).notNull(),
stock: integer('stock').notNull().default(0),
categoryId: integer('category_id').notNull(),
createdAt: timestamp('created_at').defaultNow(),
updatedAt: timestamp('updated_at').defaultNow()
});
// Use in routes
import { db } from '../config/database';
// Select with conditions
const activeProducts = await db.select()
.from(products)
.where(and(
gte(products.stock, 1),
lte(products.price, 100)
))
.orderBy(desc(products.createdAt));
// Insert
const newProduct = await db.insert(products)
.values({
name: 'New Product',
price: '29.99',
stock: 50,
categoryId: 1
})
.returning();
// Update
await db.update(products)
.set({ stock: 100, updatedAt: new Date() })
.where(eq(products.id, 1));
// Delete
await db.delete(products)
.where(eq(products.id, 1));
// Complex joins
const productsWithCategories = await db.select({
product: products,
category: categories
})
.from(products)
.innerJoin(categories, eq(products.categoryId, categories.id))
.where(eq(products.stock, 0));
// Generate migrations
// bun run db:generate
// bun run db:migrate
Modern web standards without framework overhead
Products
Products
// packages/client/src/pages/products.ts
import { api } from '../lib/api';
import { requireAuth } from '../lib/auth';
import '../styles/main.css';
requireAuth(); // Redirect if not logged in
interface Product {
id: number;
name: string;
price: string;
stock: number;
}
async function loadProducts() {
const products: Product[] = await api.get('/api/products');
const container = document.getElementById('products-list');
if (!container) return;
container.innerHTML = products.map(product => `
${escapeHtml(product.name)}
$${product.price}
Stock: ${product.stock}
`).join('');
}
function escapeHtml(text: string): string {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
(window as any).addToCart = async (productId: number) => {
await api.post('/api/cart/add', { productId, quantity: 1 });
alert('Added to cart!');
};
loadProducts();
Try adjusting your search or filters
These blueprints are production-ready patterns you can implement immediately. Upgrade to Pro for 500+ more examples and advanced features.