Skip to content

Deno Fresh Backend API โ€‹

HaloLight Deno backend API is built on Fresh framework and Deno KV, using the native Deno runtime to provide high-performance RESTful API services.

API Documentation: https://halolight-deno.h7ml.cn/docs

GitHub: https://github.com/halolight/halolight-deno

Features โ€‹

  • ๐Ÿ” JWT Dual Tokens - Access Token + Refresh Token with auto-renewal
  • ๐Ÿ›ก๏ธ RBAC Permissions - Role-based access control with wildcard matching
  • ๐Ÿ“ก RESTful API - Standardized interface design with OpenAPI documentation
  • ๐Ÿ’พ Deno KV - Built-in key-value storage, no external database needed
  • โšก Islands Architecture - Partial hydration for extreme performance
  • โœ… Data Validation - Request parameter validation and error handling
  • ๐Ÿ“Š Logging System - Request logs and error tracking
  • ๐Ÿณ Docker Support - Containerized deployment

Tech Stack โ€‹

TechnologyVersionDescription
Deno2.xRuntime (built-in TypeScript)
Fresh1.xDeno-native web framework
Preact10.xLightweight UI library
Deno KV-Built-in key-value storage (database)
Hono4.xAPI routing framework (optional)
JWT-Authentication
Tailwind CSS3.xAtomic CSS

Quick Start โ€‹

Requirements โ€‹

  • Deno >= 2.0.0

Installation โ€‹

bash
# Clone repository
git clone https://github.com/halolight/halolight-deno.git
cd halolight-deno

# No dependency install needed, Deno manages automatically

Environment Variables โ€‹

bash
cp .env.example .env
env
# API Configuration
API_URL=/api
USE_MOCK=true

# JWT Secret
JWT_SECRET=your-super-secret-key
JWT_ACCESS_EXPIRES=15m
JWT_REFRESH_EXPIRES=7d

# Deno KV (optional, local by default)
DENO_KV_PATH=./data/kv.db

# Service Configuration
PORT=8000
NODE_ENV=development

# Demo Account
DEMO_EMAIL=admin@halolight.h7ml.cn
DEMO_PASSWORD=123456
SHOW_DEMO_HINT=false

# Brand Configuration
APP_TITLE=Admin Pro
BRAND_NAME=Halolight

Database Initialization โ€‹

bash
# Deno KV requires no migration, auto-creates
# If seed data needed
deno task seed

Start Service โ€‹

bash
# Development mode
deno task dev

# Production mode
deno task build
deno task start

Visit http://localhost:8000

Project Structure โ€‹

halolight-deno/
โ”œโ”€โ”€ routes/                  # Route handlers
โ”‚   โ”œโ”€โ”€ api/                 # API endpoints
โ”‚   โ”‚   โ”œโ”€โ”€ auth/            # Auth routes
โ”‚   โ”‚   โ”œโ”€โ”€ users/           # User routes
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard/       # Dashboard routes
โ”‚   โ”‚   โ”œโ”€โ”€ documents/       # Document routes
โ”‚   โ”‚   โ”œโ”€โ”€ files/           # File routes
โ”‚   โ”‚   โ”œโ”€โ”€ messages/        # Message routes
โ”‚   โ”‚   โ”œโ”€โ”€ notifications/   # Notification routes
โ”‚   โ”‚   โ””โ”€โ”€ calendar/        # Calendar routes
โ”‚   โ”œโ”€โ”€ (auth)/              # Auth pages
โ”‚   โ”‚   โ”œโ”€โ”€ login.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ register.tsx
โ”‚   โ”‚   โ””โ”€โ”€ forgot-password.tsx
โ”‚   โ””โ”€โ”€ (dashboard)/         # Dashboard pages
โ”‚       โ”œโ”€โ”€ index.tsx
โ”‚       โ”œโ”€โ”€ users.tsx
โ”‚       โ””โ”€โ”€ settings.tsx
โ”œโ”€โ”€ utils/                   # Utilities
โ”‚   โ”œโ”€โ”€ auth.ts              # Auth utilities
โ”‚   โ”œโ”€โ”€ kv.ts                # Deno KV wrapper
โ”‚   โ”œโ”€โ”€ permissions.ts       # Permission checks
โ”‚   โ”œโ”€โ”€ jwt.ts               # JWT utilities
โ”‚   โ””โ”€โ”€ validation.ts        # Data validation
โ”œโ”€โ”€ islands/                 # Interactive components (client-side)
โ”‚   โ”œโ”€โ”€ AuthProvider.tsx
โ”‚   โ”œโ”€โ”€ ThemeToggle.tsx
โ”‚   โ””โ”€โ”€ Dashboard.tsx
โ”œโ”€โ”€ components/              # UI components
โ”‚   โ”œโ”€โ”€ ui/
โ”‚   โ”œโ”€โ”€ layout/
โ”‚   โ””โ”€โ”€ dashboard/
โ”œโ”€โ”€ static/                  # Static assets
โ”œโ”€โ”€ fresh.gen.ts             # Fresh generated file
โ”œโ”€โ”€ fresh.config.ts          # Fresh config
โ”œโ”€โ”€ deno.json                # Deno config
โ””โ”€โ”€ import_map.json          # Import map

API Modules โ€‹

Authentication Endpoints โ€‹

MethodPathDescriptionPermission
POST/api/auth/loginUser loginPublic
POST/api/auth/registerUser registrationPublic
POST/api/auth/refreshRefresh tokenPublic
POST/api/auth/logoutUser logoutAuthenticated
POST/api/auth/forgot-passwordForgot passwordPublic
POST/api/auth/reset-passwordReset passwordPublic

User Management Endpoints โ€‹

MethodPathDescriptionPermission
GET/api/usersGet user listusers:view
GET/api/users/:idGet user detailsusers:view
POST/api/usersCreate userusers:create
PUT/api/users/:idUpdate userusers:update
DELETE/api/users/:idDelete userusers:delete
GET/api/users/meGet current userAuthenticated

Complete Endpoint List โ€‹

Document Management (Documents) - 5 endpoints โ€‹

MethodPathDescription
GET/api/documentsGet document list
GET/api/documents/:idGet document details
POST/api/documentsCreate document
PUT/api/documents/:idUpdate document
DELETE/api/documents/:idDelete document

File Management (Files) - 5 endpoints โ€‹

MethodPathDescription
GET/api/filesGet file list
GET/api/files/:idGet file details
POST/api/files/uploadUpload file
PUT/api/files/:idUpdate file info
DELETE/api/files/:idDelete file

Message Management (Messages) - 5 endpoints โ€‹

MethodPathDescription
GET/api/messagesGet message list
GET/api/messages/:idGet message details
POST/api/messagesSend message
PUT/api/messages/:id/readMark as read
DELETE/api/messages/:idDelete message

Notification Management (Notifications) - 4 endpoints โ€‹

MethodPathDescription
GET/api/notificationsGet notification list
PUT/api/notifications/:id/readMark as read
PUT/api/notifications/read-allMark all as read
DELETE/api/notifications/:idDelete notification

Calendar Management (Calendar) - 5 endpoints โ€‹

MethodPathDescription
GET/api/calendar/eventsGet event list
GET/api/calendar/events/:idGet event details
POST/api/calendar/eventsCreate event
PUT/api/calendar/events/:idUpdate event
DELETE/api/calendar/events/:idDelete event

Dashboard - 6 endpoints โ€‹

MethodPathDescription
GET/api/dashboard/statsStatistics data
GET/api/dashboard/visitsVisit trends
GET/api/dashboard/salesSales data
GET/api/dashboard/piePie chart data
GET/api/dashboard/tasksTodo tasks
GET/api/dashboard/calendarToday's schedule

Authentication โ€‹

JWT Dual Tokens โ€‹

Access Token:  15-minute validity for API requests
Refresh Token: 7-day validity for refreshing Access Token

Request Headers โ€‹

http
Authorization: Bearer <access_token>

Refresh Flow โ€‹

typescript
// utils/jwt.ts
import { create, verify } from "https://deno.land/x/djwt@v3.0.0/mod.ts";

const key = await crypto.subtle.generateKey(
  { name: "HMAC", hash: "SHA-256" },
  true,
  ["sign", "verify"],
);

export async function createAccessToken(userId: string): Promise<string> {
  return await create(
    { alg: "HS256", typ: "JWT" },
    { userId, exp: Date.now() + 15 * 60 * 1000 }, // 15 minutes
    key,
  );
}

export async function refreshToken(refreshToken: string): Promise<string> {
  const payload = await verify(refreshToken, key);
  return await createAccessToken(payload.userId as string);
}

Permission System โ€‹

Role Definitions โ€‹

RoleDescriptionPermissions
super_adminSuper Administrator* (all permissions)
adminAdministratorusers:*, documents:*, files:*, messages:*, calendar:*
userRegular Userdocuments:view, files:view, messages:view, calendar:view
guestGuestdashboard:view

Permission Format โ€‹

{resource}:{action}

Examples:
- users:view      # View users
- users:create    # Create users
- users:*         # All user operations
- *               # All permissions

Permission Check Implementation โ€‹

typescript
// utils/permissions.ts
export function hasPermission(user: User, permission: string): boolean {
  const userPermissions = user.permissions || [];

  return userPermissions.some((p) => {
    if (p === "*") return true;
    if (p.endsWith(":*")) {
      const resource = p.slice(0, -2);
      return permission.startsWith(resource + ":");
    }
    return p === permission;
  });
}

// Route middleware
export function requirePermission(permission: string) {
  return async (req: Request, ctx: any) => {
    const user = ctx.state.user;
    if (!hasPermission(user, permission)) {
      return new Response("Forbidden", { status: 403 });
    }
    return await ctx.next();
  };
}

Error Handling โ€‹

Error Response Format โ€‹

json
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request parameter validation failed",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  }
}

Error Codes โ€‹

StatusError CodeDescription
400VALIDATION_ERRORParameter validation failed
401UNAUTHORIZEDUnauthorized
403FORBIDDENForbidden
404NOT_FOUNDResource not found
409CONFLICTResource conflict
500INTERNAL_ERRORServer error

Common Commands โ€‹

bash
# Development
deno task dev              # Start dev server (hot reload)

# Build
deno task build            # Build production bundle

# Testing
deno test                  # Run tests
deno test --coverage       # Test coverage

# Database
deno task seed             # Initialize seed data

# Code Quality
deno lint                  # Lint
deno fmt                   # Format
deno check **/*.ts         # Type check

Deployment โ€‹

Docker โ€‹

bash
docker build -t halolight-deno .
docker run -p 8000:8000 halolight-deno

Docker Compose โ€‹

bash
docker-compose up -d
yaml
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
    environment:
      - NODE_ENV=production
      - JWT_SECRET=${JWT_SECRET}
      - DENO_KV_PATH=/data/kv.db
    volumes:
      - deno_kv_data:/data
    restart: unless-stopped

volumes:
  deno_kv_data:
bash
# Install deployctl
deno install -Arf jsr:@deno/deployctl

# Deploy to Deno Deploy
deployctl deploy --project=halolight-deno main.ts

Production Configuration โ€‹

env
NODE_ENV=production
JWT_SECRET=your-production-secret-key-min-32-chars
DENO_KV_PATH=/data/kv.db
PORT=8000

Testing โ€‹

Run Tests โ€‹

bash
deno test                  # Run all tests
deno test --coverage       # Generate coverage report
deno test --watch          # Watch mode

Test Examples โ€‹

typescript
// routes/api/auth/_test.ts
import { assertEquals } from "https://deno.land/std@0.208.0/assert/mod.ts";

Deno.test("POST /api/auth/login - success", async () => {
  const response = await fetch("http://localhost:8000/api/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "admin@halolight.h7ml.cn",
      password: "123456",
    }),
  });

  assertEquals(response.status, 200);
  const data = await response.json();
  assertEquals(data.success, true);
  assertEquals(typeof data.data.accessToken, "string");
});

Deno.test("POST /api/auth/login - invalid credentials", async () => {
  const response = await fetch("http://localhost:8000/api/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "wrong@example.com",
      password: "wrong",
    }),
  });

  assertEquals(response.status, 401);
  const data = await response.json();
  assertEquals(data.success, false);
});

Performance Metrics โ€‹

Benchmarks โ€‹

MetricValueNotes
Request Throughput~45,000 req/sDeno 2.0, single core, wrk test
Average Response Time<5msLocal Deno KV, no external deps
Memory Usage~30MBBase memory after startup
CPU Usage<10%Idle state

Observability โ€‹

Logging System โ€‹

typescript
// utils/logger.ts
import { Logger } from "https://deno.land/std@0.208.0/log/mod.ts";

const logger = new Logger("app");

export function logRequest(req: Request, res: Response, duration: number) {
  logger.info(
    `${req.method} ${new URL(req.url).pathname} ${res.status} ${duration}ms`,
  );
}

export function logError(error: Error, context?: any) {
  logger.error(`Error: ${error.message}`, { error, context });
}

Health Check โ€‹

typescript
// routes/api/health.ts
export const handler = async (req: Request): Promise<Response> => {
  try {
    // Check Deno KV connection
    const kv = await Deno.openKv();
    await kv.get(["health"]);
    await kv.close();

    return Response.json({
      status: "healthy",
      timestamp: new Date().toISOString(),
      uptime: Deno.memoryUsage(),
    });
  } catch (error) {
    return Response.json(
      { status: "unhealthy", error: error.message },
      { status: 503 },
    );
  }
};

Monitoring Metrics โ€‹

typescript
// utils/metrics.ts
const metrics = {
  requests: 0,
  errors: 0,
  responseTime: [] as number[],
};

export function recordRequest(duration: number) {
  metrics.requests++;
  metrics.responseTime.push(duration);
}

export function recordError() {
  metrics.errors++;
}

export function getMetrics() {
  const avg = metrics.responseTime.reduce((a, b) => a + b, 0) /
    metrics.responseTime.length;
  return {
    totalRequests: metrics.requests,
    totalErrors: metrics.errors,
    avgResponseTime: avg || 0,
  };
}

FAQ โ€‹

Q: How to persist Deno KV data? โ€‹

A: Configure the DENO_KV_PATH environment variable to specify the data file path.

bash
# .env
DENO_KV_PATH=./data/kv.db
typescript
// Use custom path
const kv = await Deno.openKv(Deno.env.get("DENO_KV_PATH"));

Q: How to enable remote Deno KV (Deno Deploy)? โ€‹

A: When deploying on Deno Deploy, using Deno.openKv() automatically connects to the hosted distributed KV.

typescript
// Production environment automatically uses remote KV
const kv = await Deno.openKv();

Q: How to handle file uploads? โ€‹

A: Use Fresh's FormData API to handle file uploads.

typescript
// routes/api/files/upload.ts
export const handler = async (req: Request): Promise<Response> => {
  const formData = await req.formData();
  const file = formData.get("file") as File;

  if (!file) {
    return Response.json({ error: "No file uploaded" }, { status: 400 });
  }

  // Save file to Deno KV or cloud storage
  const bytes = await file.arrayBuffer();
  const kv = await Deno.openKv();
  await kv.set(["files", crypto.randomUUID()], {
    name: file.name,
    type: file.type,
    size: file.size,
    data: new Uint8Array(bytes),
  });

  return Response.json({ success: true });
};

Q: How does Islands architecture integrate with APIs? โ€‹

A: Islands are client-side interactive components that call backend APIs via fetch.

typescript
// islands/UserList.tsx
import { useSignal } from "@preact/signals";
import { useEffect } from "preact/hooks";

export default function UserList() {
  const users = useSignal([]);

  useEffect(() => {
    fetch("/api/users")
      .then((res) => res.json())
      .then((data) => users.value = data);
  }, []);

  return (
    <div>
      {users.value.map((user) => (
        <div key={user.id}>{user.name}</div>
      ))}
    </div>
  );
}

Development Tools โ€‹

  • Deno VSCode Extension - Official VS Code plugin with IntelliSense and debugging
  • deployctl - Deno Deploy command-line tool
  • wrk / autocannon - HTTP stress testing tools
  • Deno Lint - Built-in code linting tool

Comparison with Other Backends โ€‹

FeatureDeno FreshNestJSFastAPISpring Boot
LanguageTypeScript (Deno)TypeScriptPythonJava
ORMDeno KVPrismaSQLAlchemyJPA
Performanceโญโญโญโญโญโญโญโญโญโญโญโญโญโญโญโญ
Learning Curveโญโญโญโญโญโญโญโญโญโญโญโญโญ
Startup Time<100ms~2s~1s~5s
Memory Usage30MB80MB50MB150MB
DeploymentDeno DeployDocker/CloudDocker/CloudDocker/Cloud