A scalable, testable, extensible, boilerplate for Sveltekit.
Sveltekit is awesome. File-based routing, SSG/SSR, and having the ability to have a backend attatched to your frontend saves incredible amounts of time and effort.
But that backend sometimes isn't enough. There are some projects that require more powerful and feature rich backends. I'm talking Middleware, guards, pipes, interceptors, testing, event-emitters, task scheduling, route versioning, and so on.
People tend to think that Sveltekit/NextJS are a backend with a frontend attached. This notion is rediculous and I'm unsure why its circulated so much. The backend for these frameworks are to facilitate the features in which their frontends promote and make them so powerful.
So whats the answer?
We want to maintain simplicity, elegancy, and a solid DX. Why not just use what appears to be silenly infered to do from the docs? Create a catch-all route and attatch a fully featured api onto the node-process sveltekit already runs on.
/api/[...slugs]
import app from '$lib/api';
import type { RequestHandler } from '@sveltejs/kit';
export const GET: RequestHandler = ({ request }) => app.fetch(request);
export const PUT: RequestHandler = ({ request }) => app.fetch(request);
export const DELETE: RequestHandler = ({ request }) => app.fetch(request);
export const POST: RequestHandler = ({ request }) => app.fetch(request);
My selection of libraries are just what I've found success, stable and high cohesion with. This repo should just serve as a guide as to whats possible; not what libary is the best.
The example boilerplate for the backend follows "Clean Architecture" in an Object Oriented Programming(OOP) manner.
For the majority of apps I create, this is how I like to define my business logic and have most success with maintaning.
└─── app
│ │ index.js // 5. Framework
│ │ register-providers.ts // import providers to be registered by the container
│ │
│ └─── common // slam things here that will be used throughout all modules
│ │ │ interfaces
│ │ │ guards
│ │ │ ...
│ │
│ └─── modules // business logic.
│ │ │ accounts
│ │ └─── accounts.repository.ts // db queries
│ │ │ accounts.service.ts // business logic
│ │ │ accounts.model.ts // db model
│ │
└─── ...
If you prefer a more funcitonal programming approach I've had success with an approach similar to the architecture below.
└─── api
│ │ app.js
│ │ database.js
│ │ ...
| |
│ └─── models
│ │ │ accounts.model.ts
│ │ │ users.model.ts
│ │ │ ...
│ │
│ └─── repositories
│ │ │ accounts.repository.ts
│ │ │ users.repository.ts
│ │ │ ...
│ │
│ └─── use-cases
│ │ └─── accounts
│ │ │ │ post-account.js
│ │ │ │ get-account-by-email.js
│ │ │ │ ...
│ │ └─── ...
│ │
│ └─── controllers // 3) Interface Adapters
│ │ │ accounts.controller.js
│ │ │ users.controller.js
│ │ │ ...
│
└─── ...
Testing probably isn't first and foremost when creating an app. Thats fine. You shoulkdn't be spending time writing tests if your app is changing and pivoting.
BUT a good stack should be testable when the time to solidify a codebase arrives. I created this stack with that pinciple in mind. I've provided a examples of how to write these tests under authentication.service.test.ts
or users.service.test.ts