Storage
Wspólne miejsce na dane w obrębie jednego żądania: użytkownika pobierasz raz, a kolejne funkcje w łańcuchu czytają go już ze storage.
storage to wspólne miejsce na dane, do którego sięgają wszystkie funkcje w łańcuchu. Zamiast
pobierać użytkownika osobno w każdej z nich, pobierasz go raz i zostawiasz tam dla pozostałych.
Domyślna implementacja trzyma wszystko w pamięci. Możesz ją podmienić na własną - również taką, która odpytuje zewnętrzną usługę.
Ostrożnie z bazą danych po drugiej stronie adaptera. Każde zapytanie wydłuża łańcuch, a razem z nim TTFB całej strony.
Zalecenie: sięgaj po magazyny klucz-wartość, czyli Redis, Vercel Edge Config i podobne.
Przykład użycia
Typowy wzorzec wygląda tak: sprawdź, czy dane już leżą w storage, a jeśli nie - pobierz je i odłóż dla kolejnych funkcji.
Każde żądanie dostaje własną instancję event, więc zawartość storage nie przechodzi między
żądaniami.
import type { NextMiddleware } from "@zanreal/nemo";
const example: NextMiddleware = async (req, { storage }) => {
let user = undefined;
if (!storage.has("user")) {
user = await fetchUser();
storage.set("user", user);
} else {
user = storage.get("user");
}
if (!user) {
return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
}
};Typowanie
set i get przyjmują parametr generyczny, więc odczytana wartość zachowuje kształt, który
zapisałeś:
interface UserData {
id: number;
name: string;
roles: string[];
}
// Store data with type
storage.set<UserData>("user", {
id: 1,
name: "John",
roles: ["admin", "editor"],
});
// Retrieve with correct type
const user = storage.get<UserData>("user");
if (user) {
// TypeScript knows the shape of user
console.log(user.name);
console.log(user.roles.join(", "));
}Własny adapter
Domyślny magazyn w pamięci podmienisz na dowolny inny, tworząc klasę rozszerzającą
StorageAdapter:
import { StorageAdapter } from "@zanreal/nemo/storage";
export class CustomStorageAdapter extends StorageAdapter {
// Implement required methods
async get<T>(key: string): T | undefined {
// Your implementation
return undefined;
}
async set<T>(key: string, value: T): void {
// Your implementation
}
async has(key: string): boolean {
// Your implementation
return false;
}
async delete(key: string): boolean {
// Your implementation
return false;
}
async clear(): void {
// Your implementation
}
// Implement other required methods
entries(): IterableIterator<[string, unknown]> {
// Your implementation
return [][Symbol.iterator]();
}
keys(): IterableIterator<string> {
// Your implementation
return [][Symbol.iterator]();
}
values(): IterableIterator<unknown> {
// Your implementation
return [][Symbol.iterator]();
}
get size(): number {
// Your implementation
return 0;
}
}Gotowy adapter przekazujesz w opcjach createNEMO() pod kluczem storage. Do wyboru masz jedną
instancję współdzieloną przez cały proces albo funkcję, która utworzy nową dla każdego żądania.
import { NEMO } from "@zanreal/nemo";
import { CustomStorageAdapter } from "./StorageAdapter";
export const middleware = createNEMO(middlewares, globalMiddleware, {
storage: new CustomStorageAdapter()
});
import { NEMO } from "@zanreal/nemo";
import { CustomStorageAdapter } from "./StorageAdapter";
export const middleware = createNEMO(middlewares, globalMiddleware, {
storage: () => new CustomStorageAdapter()
});
Czy ta strona była pomocna?
M↓obsługiwane.