A modern, production-ready full-stack template combining SvelteKit, Hono, and Cloudflare Workers with enterprise-grade architecture patterns including dependency injection, comprehensive testing, and global error handling.
This project implements a clean architecture using InversifyJS for dependency injection, following SOLID principles for maintainable and testable code.
Service | Purpose | Scope |
---|---|---|
UserService |
User business logic and orchestration | Transient |
UserRepository |
Data access and persistence | Singleton |
Logger |
Structured logging with context | Singleton |
ConfigService |
Environment and app configuration | Singleton |
// In your API routes
import { getUserService, getLogger } from '../container/resolvers';
app.get('/users', async (c) => {
const userService = getUserService(c);
const logger = getLogger(c);
logger.info('Fetching users');
const users = await userService.getAllUsers();
return c.json({ success: true, data: users });
});
# Clone and install
git clone <your-repo-url>
cd sveltekit-hono
pnpm install
# Start development
pnpm dev
That's it! Visit http://localhost:5173
# Install Wrangler CLI (one-time setup)
npm install -g wrangler
# Run with Cloudflare Workers simulation
pnpm dev:cf
pnpm dev # SvelteKit dev server (recommended)
pnpm dev:cf # Cloudflare Workers simulation
pnpm build # Production build
pnpm preview # Preview built app
pnpm test # Tests in watch mode
pnpm test:run # Run all tests once
pnpm test:ui # Interactive test UI
pnpm test:coverage # Coverage reports
pnpm check # TypeScript validation
pnpm lint # Code linting
pnpm format # Code formatting
pnpm deploy # Deploy to dev
pnpm deploy:cf # Deploy to production
Built with Hono and comprehensive error handling:
Method | Endpoint | Description |
---|---|---|
GET |
/api/health |
System health check |
GET |
/api/hello |
API info and request details |
Method | Endpoint | Description | Status Codes |
---|---|---|---|
GET |
/api/users |
List all users | 200, 500 |
GET |
/api/users/:id |
Get user by ID | 200, 400, 404, 500 |
POST |
/api/users |
Create new user | 201, 400, 409, 500 |
PUT |
/api/users/:id |
Update user | 200, 400, 404, 500 |
DELETE |
/api/users/:id |
Delete user | 200, 400, 404, 500 |
Consistent JSON responses across all endpoints:
// Success
{ "success": true, "data": any, "message?": string, "timestamp": string }
// Error
{ "success": false, "error": string, "timestamp": string }
# Health check
curl http://localhost:5173/api/health
# List users (demo data)
curl http://localhost:5173/api/users
# Create user
curl -X POST http://localhost:5173/api/users \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"[email protected]"}'
Custom Error Classes with proper HTTP status codes:
ValidationError
(400) - Invalid input dataNotFoundError
(404) - Resource not foundConflictError
(409) - Duplicate resourcesBadRequestError
, UnauthorizedError
, ForbiddenError
, InternalServerError
Global Error Handler catches all exceptions and returns consistent JSON responses with structured logging.
Comprehensive test suite with Vitest + Testing Library:
# Run tests
pnpm test:run # All tests once
pnpm test # Watch mode
pnpm test:ui # Interactive UI
pnpm test:coverage # With coverage
Input validation is implemented with Zod v4. Schemas live in src/models/user.model.ts
and types are inferred directly from the schemas for end-to-end type safety.
// src/models/user.model.ts
import { z } from 'zod';
export const createUserSchema = z.object({
name: z
.string()
.trim()
.min(1, { message: 'Name is required' })
.refine((v) => v.length === 0 || v.length >= 2, {
message: 'Name must be at least 2 characters long'
}),
email: z
.string()
.trim()
.min(1, { message: 'Email is required' })
.refine((v) => v.length === 0 || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v), {
message: 'Email format is invalid'
})
});
export type CreateUserRequest = z.infer<typeof createUserSchema>;
Services validate using safeParse
and throw a ValidationError
on failure:
// src/services/user.service.ts
const parsed = createUserSchema.safeParse(userData);
if (!parsed.success) {
const messages = parsed.error.issues.map((i) => i.message);
throw new ValidationError(`Validation failed: ${messages.join(', ')}`);
}
src/
โโโ routes/ # SvelteKit routes
โ โโโ +page.svelte # Demo page
โ โโโ api/[...paths]/+server.ts # Hono API server
โโโ container/ # Dependency Injection
โ โโโ inversify.config.ts # IoC container
โ โโโ types.ts # Service types
โ โโโ resolvers.ts # Service resolvers
โโโ models/ # Domain models and schemas (Zod)
โ โโโ user.model.ts # User model + Zod schemas
โ โโโ error.model.ts # Custom error classes and mapping
โโโ interfaces/ # TypeScript interfaces
โโโ services/ # Business logic layer
โโโ types/ # Type definitions
โโโ tests/ # Test suites
โโโ api/ # API tests
โโโ components/ # Component tests
Key Files:
wrangler.toml
- Cloudflare Workers configurationsvelte.config.js
- SvelteKit + adapter setupvite.config.ts
- Vite + testing configuration# One-time setup
wrangler login
# Deploy to development
pnpm deploy
# Deploy to production
pnpm deploy:cf
.env.local
(SvelteKit)wrangler.toml
(Cloudflare Workers)Using InversifyJS for clean architecture:
pnpm install
git checkout -b feature/your-feature
pnpm test:run && pnpm lint && pnpm check
Ensure all tests pass and follow the existing code patterns.
API routes not working?
wrangler.toml
configuration+server.ts
Environment variables?
PUBLIC_
wrangler.toml
Build errors?
pnpm check
for TypeScript validationTest failures?
pnpm test:ui
for interactive debuggingโก๏ธ See DEVELOPMENT.md for detailed troubleshooting
MIT License - see LICENSE file.
Give a โญ if this helped you!
Built with โค๏ธ using SvelteKit + Hono + Cloudflare Workers