From d78eb517ed05d0efb06fe9f9fe18a339fb545194 Mon Sep 17 00:00:00 2001 From: Braden Wong Date: Sat, 6 Dec 2025 14:27:56 -0800 Subject: [PATCH] docs: show multiple service patterns with tabs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Present all four approaches for grouping service functions (plain object, module exports, namespace, abstract class) using tabs, letting developers choose based on their background and preferences. Add tip callouts in other locations pointing to this central reference. Changes: - Add Tab component to best-practice.md with 4 pattern options - Add "Module Exports" pattern (import * as) for ES module-native approach - Reorder patterns: Plain Object → Module Exports → Namespace → Abstract Class - Add tip callout after Controller "Do" example linking to Service patterns - Add tip callout in key-concept.md linking to Service patterns - Update main service.ts example to use plain object (simplest approach) --- docs/essential/best-practice.md | 112 +++++++++++++++++++++++++++++--- docs/key-concept.md | 4 ++ 2 files changed, 107 insertions(+), 9 deletions(-) diff --git a/docs/essential/best-practice.md b/docs/essential/best-practice.md index 9e32090d..0959b211 100644 --- a/docs/essential/best-practice.md +++ b/docs/essential/best-practice.md @@ -14,6 +14,10 @@ head: content: Elysia is a pattern agnostic framework, we leave the decision up to you and your team for coding patterns to use. However, we found that there are several who are using MVC pattern (Model-View-Controller) on Elysia, and found it's hard to decouple and handle types. This page is a guide to use Elysia with MVC pattern. --- + + # Best Practice Elysia is a pattern-agnostic framework, leaving the decision of which coding patterns to use up to you and your team. @@ -85,10 +89,9 @@ import { status } from 'elysia' import type { AuthModel } from './model' -// If the class doesn't need to store a property, -// you may use `abstract class` to avoid class allocation -export abstract class Auth { - static async signIn({ username, password }: AuthModel.signInBody) { +// Group related functions - see Service section for alternative patterns +export const Auth = { + async signIn({ username, password }: AuthModel.signInBody) { const user = await sql` SELECT password FROM users @@ -211,6 +214,10 @@ new Elysia() .get('/', ({ stuff }) => Controller.doStuff(stuff)) ``` +::: tip +This example uses an abstract class, but you can also use plain objects, module exports, or namespaces. See [Service patterns](#1-abstract-away-non-request-dependent-service) for alternatives. +::: + Tying the controller to Elysia Context may lead to: 1. Loss of type integrity 2. Make it harder to test and reuse @@ -280,16 +287,99 @@ There are 2 types of service in Elysia: We recommend abstracting a service class/function away from Elysia. -If the service or function isn't tied to an HTTP request or doesn't access a `Context`, it's recommended to implement it as a static class or function. +If the service or function isn't tied to an HTTP request or doesn't access a `Context`, you can group related functions using several patterns depending on your preference: + + + + + + + + + + + + + +All four patterns produce the same runtime behavior. Choose based on your team's familiarity and whether you need to co-locate types. ### 2. Request dependent service as Elysia instance diff --git a/docs/key-concept.md b/docs/key-concept.md index b831b42d..c3aa7109 100644 --- a/docs/key-concept.md +++ b/docs/key-concept.md @@ -326,6 +326,10 @@ const app = new Elysia() }) ``` +::: tip +This example uses an abstract class, but you can also use plain objects, module exports, or namespaces. See [Best Practice: Service patterns](/essential/best-practice.html#1-abstract-away-non-request-dependent-service) for alternatives. +::: + See [Best practice: MVC Controller](/essential/best-practice.html#controller). ### TypeScript