Middleware błędów i typy Result
Projektowanie centralnego handlera błędów i typowanego wzorca Result, opakowywanie handlerów asynchronicznych w celu przekazywania błędów oraz zwracanie spójnych obiektów błędów
Middleware błędów i typy Result to bezpłatna lekcja TypeScript Academy na CoddyKit. To lekcja 3 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej TypeScript Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs TypeScript Academy zawiera 3 lekcji w sumie.
Wprowadzenie
Cel: Scentralizować błędy występujące w czasie działania i zwracać spójną „kopertę błędu” w formacie JSON. Należy utworzyć typ Result, asynchroniczny wrapper oraz solidne middleware obsługi błędów.
- Rozróżnialna unia Result<T,E>
- next(err) z asynchronicznych handlerów
- Mapowanie Unknown na typowany błąd
Typ Result
Należy używać rozróżnialnej unii do opisywania wyników funkcji: { ok: true; value } albo { ok: false; error }. Kod wywołujący musi obsłużyć obie gałęzie.
// Result pattern for services and controllers
export type Ok<T> = { ok: true; value: T }
export type Err<E> = { ok: false; error: E }
export type Result<T, E = string> = Ok<T> | Err<E>
export const ok = <T>(value: T): Ok<T> => ({ ok: true, value })
export const err = <E>(error: E): Err<E> => ({ ok: false, error })
// Example usage
async function getUserName(id: string): Promise<Result<string, "NOT_FOUND" | "DB">> {
if (id === "missing") return err("NOT_FOUND")
try { return ok("Ada") } catch { return err("DB") }
}Ujednolicony format błędu
Należy normalizować unknown do niewielkiego, przewidywalnego formatu. Nie wolno ujawniać klientom śladów stosu.
// Canonical error envelope
export type ErrorEnvelope = {
error: string
code?: string
details?: unknown
}
export function mapError(u: unknown): ErrorEnvelope {
if (u instanceof Error) return { error: u.message }
if (typeof u === "string") return { error: u }
try { return { error: JSON.stringify(u) } } catch { return { error: "Unknown error" } }
}Asynchroniczny wrapper + middleware
Należy opakować dowolny handler async, aby odrzucenia wywoływały next(err). Końcowe middleware obsługi błędów formatuje JSON tylko raz.
import express, { Request, Response, NextFunction } from "express"
export const asyncHandler = <P, ResBody, ReqBody, Query>(fn: (req: Request<P, ResBody, ReqBody, Query>, res: Response<ResBody>, next: NextFunction) => Promise<unknown>) => {
return (req: Request<P, ResBody, ReqBody, Query>, res: Response<ResBody>, next: NextFunction) => {
Promise.resolve(fn(req, res, next)).catch(next)
}
}
export function errorMiddleware(err: unknown, _req: Request, res: Response, _next: NextFunction) {
const env = mapError(err)
const status = env.code === "NOT_FOUND" ? 404 : 500
res.status(status).json(env)
}
// Usage
// app.get("/", asyncHandler(async (req, res) => { throw new Error("boom") }))
// app.use(errorMiddleware)Trasy + integracja
Należy połączyć walidację z obsługą błędów: walidacja zwraca 400 ze szczegółami, a pozostałe odrzucenia są przechwytywane przez centralne middleware.
import express from "express"
import { z } from "zod"
import { asyncHandler, errorMiddleware } from "./errors"
const createUserSchema = z.object({ name: z.string().min(1) })
const app = express()
app.use(express.json())
app.post("/users", asyncHandler(async (req, res) => {
const parsed = createUserSchema.safeParse(req.body)
if (!parsed.success) {
res.status(400).json({ error: "Invalid body", details: parsed.error.format() })
return
}
res.status(201).json({ id: "u_1", name: parsed.data.name })
}))
app.use(errorMiddleware)
app.listen(3000, () => console.log("http://localhost:3000"))Wskazówki
Wskazówki:
- Szczegóły należy logować po stronie serwera, a klientowi zwracać minimalne komunikaty.
- W usługach warto preferować typowany Result, a na granicy systemu mapować go na HTTP.
- Nie wolno ignorować odrzuceń — zawsze należy wywoływać
next(err).
Sprawdzenie błędów asynchronicznych
Szybkie sprawdzenie: Który wzorzec poprawnie przekazuje błędy asynchroniczne?
Podsumowanie
Podsumowanie: Należy używać unii Result w logice domenowej, opakowywać asynchroniczne handlery tak, aby wywoływały next, oraz formatować błędy tylko raz w końcowym middleware.
Często zadawane pytania
Czy lekcja „Middleware błędów i typy Result” jest bezpłatna?
Tak — pełny tekst „Middleware błędów i typy Result” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu TypeScript Academy, przejdź na CoddyKit PRO. Kurs TypeScript Academy zawiera 3 lekcji w sumie.
Co nauczysz się w „Middleware błędów i typy Result”?
Projektowanie centralnego handlera błędów i typowanego wzorca Result, opakowywanie handlerów asynchronicznych w celu przekazywania błędów oraz zwracanie spójnych obiektów błędów Ćwiczysz TypeScript Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć TypeScript Academy?
Nie wymagamy żadnego doświadczenia. TypeScript Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 3.
Ile czasu zajmuje lekcja „Middleware błędów i typy Result”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji TypeScript Academy?
Tak. Każda lekcja TypeScript Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Typowanie handlerów routera, Request/Response
- Walidacja schematów za pomocą zod i inferencja do TS
- Middleware błędów i typy Result