Real-World Examples
Learn by Example
Copy & Paste Code
Production-ready examples you can copy directly into your project.
Basic CRUD API
Complete REST API with tRPC, Prisma, and Zod validation for a blog application.
tRPCPrismaZod
// routers/post.router.ts
import { createTRPCRouter, publicProcedure } from '@natiwo/api';
import { z } from 'zod';
import { db } from '../database';
export const postRouter = createTRPCRouter({
list: publicProcedure
.input(z.object({
limit: z.number().min(1).max(100).default(10),
cursor: z.string().optional(),
}))
.query(async ({ input }) => {
const posts = await db.post.findMany({
take: input.limit + 1,
cursor: input.cursor ? { id: input.cursor } : undefined,
orderBy: { createdAt: 'desc' },
});
const hasNextPage = posts.length > input.limit;
const items = hasNextPage ? posts.slice(0, -1) : posts;
return {
items,
nextCursor: hasNextPage ? items[items.length - 1].id : undefined,
};
}),
create: publicProcedure
.input(z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
}))
.mutation(async ({ input }) => {
return db.post.create({
data: input,
});
}),
});Authentication with JWT
User authentication with JWT tokens, password hashing, and role-based access control.
JWTRBACAuth
// routers/auth.router.ts
import { createTRPCRouter, publicProcedure } from '@natiwo/api';
import { JWTManager } from '@natiwo/auth';
import { hashPassword, verifyPassword } from '@natiwo/crypto';
import { z } from 'zod';
import { db } from '../database';
const jwt = new JWTManager({
secret: process.env.JWT_SECRET!,
expiresIn: '7d',
});
export const authRouter = createTRPCRouter({
register: publicProcedure
.input(z.object({
email: z.string().email(),
password: z.string().min(8),
name: z.string(),
}))
.mutation(async ({ input }) => {
const hashedPassword = await hashPassword(input.password);
const user = await db.user.create({
data: {
email: input.email,
password: hashedPassword,
name: input.name,
},
});
const token = await jwt.sign({
userId: user.id,
role: 'user'
});
return { token, user };
}),
login: publicProcedure
.input(z.object({
email: z.string().email(),
password: z.string(),
}))
.mutation(async ({ input }) => {
const user = await db.user.findUnique({
where: { email: input.email },
});
if (!user) {
throw new Error('Invalid credentials');
}
const valid = await verifyPassword(input.password, user.password);
if (!valid) {
throw new Error('Invalid credentials');
}
const token = await jwt.sign({
userId: user.id,
role: user.role
});
return { token, user };
}),
});File Upload to S3
Upload files to S3 with presigned URLs, streaming, and automatic cleanup.
S3UploadStreaming
// routers/upload.router.ts
import { createTRPCRouter, protectedProcedure } from '@natiwo/api';
import { S3Storage } from '@natiwo/storage';
import { z } from 'zod';
const storage = new S3Storage({
bucket: process.env.S3_BUCKET!,
region: process.env.AWS_REGION!,
});
export const uploadRouter = createTRPCRouter({
getUploadUrl: protectedProcedure
.input(z.object({
filename: z.string(),
contentType: z.string(),
}))
.mutation(async ({ input }) => {
const key = `uploads/${Date.now()}-${input.filename}`;
const uploadUrl = await storage.getPresignedUrl({
key,
operation: 'put',
contentType: input.contentType,
expiresIn: 3600,
});
return { uploadUrl, key };
}),
confirmUpload: protectedProcedure
.input(z.object({
key: z.string(),
}))
.mutation(async ({ input, ctx }) => {
const exists = await storage.exists(input.key);
if (!exists) {
throw new Error('File not found');
}
// Save to database
const file = await db.file.create({
data: {
key: input.key,
userId: ctx.user.id,
url: storage.getPublicUrl(input.key),
},
});
return file;
}),
});Background Job Processing
Process background jobs with BullMQ, retries, and progress tracking.
BullMQJobsQueue
// jobs/email.processor.ts
import { QueueProcess } from '@natiwo/queue';
import { sendEmail } from '../lib/email';
export class EmailProcessor {
@QueueProcess('email', 'send')
async sendEmail(job: { data: { to: string; subject: string; body: string } }) {
const { to, subject, body } = job.data;
await sendEmail({
to,
subject,
body,
});
return { sent: true };
}
@QueueProcess('email', 'batch')
async sendBatchEmail(job: { data: { users: Array<{ email: string }> } }) {
const { users } = job.data;
const total = users.length;
for (let i = 0; i < users.length; i++) {
await sendEmail({
to: users[i].email,
subject: 'Newsletter',
body: 'Welcome!',
});
// Update progress
await job.updateProgress(Math.round(((i + 1) / total) * 100));
}
return { sent: total };
}
}
// Usage in router
import { createTRPCRouter, protectedProcedure } from '@natiwo/api';
import { QueueService } from '@natiwo/queue';
export const emailRouter = createTRPCRouter({
send: protectedProcedure
.input(z.object({
to: z.string().email(),
subject: z.string(),
body: z.string(),
}))
.mutation(async ({ input }) => {
const queue = new QueueService('email');
const job = await queue.add('send', input, {
attempts: 3,
backoff: {
type: 'exponential',
delay: 2000,
},
});
return { jobId: job.id };
}),
});Observability Setup
Complete observability with logging, metrics, APM, and error tracking.
LoggingMetricsAPM
// lib/observability.ts
import { createLogger } from '@natiwo/observability';
import { MetricsCollector } from '@natiwo/observability';
import { SentryErrorTracker } from '@natiwo/observability';
// Logger
export const logger = createLogger('winston', {
level: process.env.LOG_LEVEL || 'info',
format: 'json',
transports: [
{ type: 'console' },
{ type: 'file', filename: 'app.log' },
],
metadata: {
service: 'api',
environment: process.env.NODE_ENV,
},
});
// Metrics
export const metrics = new MetricsCollector({
prefix: 'natiwo_api',
exporters: ['prometheus'],
});
// Error Tracking
export const errorTracker = new SentryErrorTracker({
dsn: process.env.SENTRY_DSN,
environment: process.env.NODE_ENV,
});
// Usage in middleware
export async function requestLogger(req, res, next) {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
logger.info('HTTP Request', {
method: req.method,
path: req.path,
status: res.statusCode,
duration,
});
metrics.histogram('http_request_duration', duration, {
method: req.method,
status: res.statusCode,
});
});
next();
}More Examples on GitHub
Check out our GitHub repository for complete example projects and templates
View on GitHub