Putting Everything Together
Now that we’ve covered Actions, Services, Repos, and Resources, let’s see them work together in a complete example.
The Complete Picture
Section titled “The Complete Picture”import { Vla } from 'vla'
// Resource: Long-lived database clientclass Database extends Vla.Resource { static readonly unwrap = "db" db = this.devStable("db", () => new DbClient())}
// Repo: Data access with memoizationclass UserRepo extends Vla.Repo { db = this.inject(Database)
findById = this.memo((id: string) => { return this.db.users.find({ id }) })}
// Service: Business logic and authorizationclass UserService extends Vla.Service { repo = this.inject(UserRepo) session = this.inject(SessionService)
async getProfile(userId: string) { // Authorization if (this.session.currentUserId !== userId) { throw new Error('Unauthorized') }
// Data access through repo const user = await this.repo.findById(userId)
// Transform for frontend return { name: user.name, email: user.email, joinedAt: user.createdAt } }}
const SessionContext = Vla.createContext<{ cookies: Cookies}>()
class SessionService extends Vla.Service { sessionCtx = this.inject(SessionContext)
get currentUserId() { const { userId } = parseSession(this.sessionCtx.cookies.get('session_id')) return userId }}
// Action: Entry point from frameworkclass ShowUserProfile extends Vla.Action { users = this.inject(UserService)
async handle(userId: string) { return this.users.getProfile(userId) }}
// Invoke from your frameworkconst profile = await ShowUserProfile.invoke('user-123')Growing Your Application
Section titled “Growing Your Application”- As your application grows, you can organize code into Modules and use Facades for cross-module communication. Learn more in Modules and Facades.
- Learn more about recommended File Structure.