# Oak Backend

> >

- **Type:** Skill
- **Install:** `agentstack add skill-j4flmao-agent-skills-oak`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [j4flmao](https://agentstack.voostack.com/s/j4flmao)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [j4flmao](https://github.com/j4flmao)
- **Source:** https://github.com/j4flmao/agent-skills/tree/main/skills/backend/deno/oak

## Install

```sh
agentstack add skill-j4flmao-agent-skills-oak
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Oak Backend

## Purpose
Define Oak backend application architecture: Deno-native HTTP server, middleware composition, router pattern, and context management with typed state, composable middleware pipeline, and type-safe routing.

## Agent Protocol

### Trigger
User request includes: `oak`, `oak backend`, `deno oak`, `oak middleware`, `oak router`, `deno http`, `oak context`, `oak typescript`.

### Input Context
- Deno version (1.40+)
- Oak version (13.x)
- Language (TypeScript)
- Database (Deno KV, MongoDB via deno_mongo, PostgreSQL via deno_postgres)
- Templating (eta, deno mustache)
- Deployment (Deno Deploy, self-hosted)

### Output Artifact
A markdown document containing:
- Project structure
- Router setup (Router class)
- Middleware composition (use, compose)
- Context (c.state, c.cookies, c.send)
- Error handling middleware
- State management (context state)
- Environment configuration (Deno.env)
- Testing (Deno.test, superdeno)

### Response Format
Produce the artifact directly. No preamble, no postamble, no explanations. No filler, no hedging. Compress output.

### Completion Criteria
- Router separates route definitions from app setup
- Middleware pipeline composed with app.use()
- Error middleware catches all exceptions
- State typed via OakMiddleware type parameter
- Tests use superdeno or fetch-based requests
- Lockfile generated and committed

### Max Response Length
4096 tokens

## Architecture Decision Trees

### Oak vs Hono vs std/http

| Criterion | Oak | Hono | std/http |
|-----------|-----|------|----------|
| Middleware ecosystem | Rich (cors, auth, rate-limit, static) | Growing (cors, etag, jwt) | Manual |
| TypeScript context typing | Generic `State` param | `c.req.valid()` | Manual |
| Router pattern | `Router({ prefix })` | Chained `.get().post()` | Switch/match |
| File upload | `ctx.request.body({ type: 'form-data' })` | `c.req.parseBody()` | Manual |
| WebSocket | `oak_websocket` | Built-in `hono/ws` | Manual |
| Community | Mature (12.x, stable) | Growing (4.x) | Std lib |

Decision: Complex middleware needs → Oak. TypeScript validation-first → Hono. Max throughput/minimal → std/http.

### Route Organization Strategy

| Scale | Pattern | Structure |
|-------|---------|-----------|
| Small () {
    const orders = await orderService.findAll()
    ctx.response.body = orders
  }

  async getById(ctx: RouterContext) {
    const id = ctx.params.id!
    const order = await orderService.findById(id)
    if (!order) {
      ctx.response.status = 404
      ctx.response.body = { error: 'Order not found' }
      return
    }
    ctx.response.body = order
  }

  async create(ctx: RouterContext) {
    const body = await ctx.request.body().value
    const order = await orderService.create(body)
    ctx.response.status = 201
    ctx.response.body = order
  }
}
```

### Step 5: Middleware Pipeline
```typescript
// src/middleware/error.ts
import type { Middleware } from 'oak'

export const errorMiddleware: Middleware = async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.response.status = err.status ?? 500
    ctx.response.body = {
      success: false,
      error: {
        code: err.code ?? 'INTERNAL_ERROR',
        message: err.message ?? 'Unexpected error',
      },
    }
    ctx.response.type = 'json'
  }
}

// src/middleware/logger.ts
import type { Middleware } from 'oak'

export const loggerMiddleware: Middleware = async (ctx, next) => {
  const start = Date.now()
  await next()
  const ms = Date.now() - start
  console.log(`${ctx.request.method} ${ctx.request.url.pathname} - ${ms}ms`)
}
```

### Step 6: Typed State Management

```typescript
// src/types/index.ts
export interface AppState {
  userId: string
  role: 'admin' | 'user'
  requestId: string
}

// src/middleware/auth.ts
import type { Middleware } from 'oak'
import type { AppState } from '../types/index.ts'

export const authMiddleware: Middleware = async (ctx, next) => {
  const token = ctx.request.headers.get('Authorization')?.slice(7)
  if (!token) {
    ctx.response.status = 401
    ctx.response.body = { error: 'Unauthorized' }
    return
  }
  const payload = await verifyJwt(token)
  ctx.state.userId = payload.sub
  ctx.state.role = payload.role
  ctx.state.requestId = crypto.randomUUID()
  await next()
}
```

### Step 7: Validation with Zod

```typescript
// src/middleware/validate.ts
import { z } from 'zod/mod.ts'
import type { Middleware } from 'oak'

export function validate(schema: z.ZodSchema): Middleware {
  return async (ctx, next) => {
    const body = ctx.request.body().value
    const result = schema.safeParse(body)
    if (!result.success) {
      ctx.response.status = 400
      ctx.response.body = {
        success: false,
        error: {
          code: 'VALIDATION_ERROR',
          details: result.error.issues,
        },
      }
      return
    }
    ctx.state.validatedBody = result.data
    await next()
  }
}
```

### Step 8: Testing
```typescript
// tests/orders_test.ts
import { createApp } from '../src/app.ts'
import { assertEquals, assertExists } from 'std/testing/asserts.ts'

Deno.test('POST /api/orders creates order', async () => {
  const app = createApp()
  const listener = app.listen({ port: 0 })

  const port = (await listener).port
  const res = await fetch(`http://localhost:${port}/api/orders`, {
    method: 'POST',
    body: JSON.stringify(validPayload),
    headers: { 'Content-Type': 'application/json' },
  })
  assertEquals(res.status, 201)

  listener.close()
})

Deno.test('GET /api/orders/:id returns 404 for missing', async () => {
  const app = createApp()
  const listener = app.listen({ port: 0 })
  const { port } = await listener
  const res = await fetch(`http://localhost:${port}/api/orders/nonexistent`)
  assertEquals(res.status, 404)
  listener.close()
})
```

## Implementation Patterns

### Pattern: Composite Router (Versioned API)

```typescript
// src/router/index.ts
import { Router } from 'oak'
import { orderRouter } from './orders.ts'
import { userRouter } from './users.ts'
import { healthRouter } from './health.ts'

const api = new Router({ prefix: '/api/v1' })
api.use('/orders', orderRouter.routes(), orderRouter.allowedMethods())
api.use('/users', userRouter.routes(), userRouter.allowedMethods())

const router = new Router()
router.use('/health', healthRouter.routes(), healthRouter.allowedMethods())
router.use('/api/v1', api.routes(), api.allowedMethods())

export { router }
```

### Pattern: Static File Serving

```typescript
import { send } from 'oak/send.ts'

// Serve static files
router.get('/static/:path+', async (ctx) => {
  await send(ctx, ctx.params.path!, {
    root: `${Deno.cwd()}/public`,
    maxage: 86400,
  })
})
```

### Pattern: CORS with Dynamic Origins

```typescript
const allowedOrigins = ['https://app.example.com', 'https://admin.example.com']

app.use(async (ctx, next) => {
  const origin = ctx.request.headers.get('Origin')
  if (origin && allowedOrigins.includes(origin)) {
    ctx.response.headers.set('Access-Control-Allow-Origin', origin)
    ctx.response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
    ctx.response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
  }
  if (ctx.request.method === 'OPTIONS') {
    ctx.response.status = 204
    return
  }
  await next()
})
```

## Production Considerations

### Error Visibility
- Log all 5xx errors with full stack traces to stderr
- Use `ctx.response.type = 'json'` before setting body to ensure content-type
- Add `X-Request-Id` header to every response for tracing
- Structure error responses consistently: `{ success: false, error: { code, message, details? } }`

### Performance Tuning
- Oak Router uses radix tree for path matching — keep prefix depth reasonable
- Avoid `JSON.parse/stringify` in hot middleware — Oak handles this internally
- Use `ctx.send()` for large file responses instead of reading into memory
- Connection pooling for database — max 10-20 connections per Deno instance
- Compile with `deno compile --v8-flags=--max-old-space-size=512` for production

### Deployment
- Deno Deploy: entrypoint is `src/app.ts` exporting `app.handle` not `app.listen`
- Docker: user `deno:alpine` image, run as non-root user
- PM2 alternative: systemd service with `Restart=always`

## Anti-Patterns

| Anti-Pattern | Why | Fix |
|-------------|-----|-----|
| Inline routes in app.ts | Not testable, violates SRP | Separate router files |
| Mixing state and middleware | State is per-request, not app-wide | Use app.state for startup info only |
| `ctx.request.body()` multiple reads | Body stream is consumed once | Call once, store in context state |
| Missing `allowedMethods()` | Returns 404 instead of 405 on wrong method | Always add `router.allowedMethods()` |
| Hardcoded CORS origins | Security issue in production | Read from env var or config |
| No type on Application | `ctx.state` is `any` | Always parameterize `Application` |

## Security Considerations
- Always validate `Content-Type` header — reject unexpected types
- Set `Deno.permissions` with exact `--allow-*` flags per deployment
- Use `secure: true` on cookies in production (HTTPS only)
- Rate limit by IP or token — store counters in Deno KV
- Sanitize `ctx.params` — Oak does not auto-escape/validate path params
- CORS: never `*` with credentials; use explicit origin list or regex matching

## Testing Strategies

### Unit Testing Services
```typescript
Deno.test('calculateOrderTotal', () => {
  const result = calculateTotal([{ price: 10, qty: 2 }, { price: 5, qty: 3 }])
  assertEquals(result, 35)
})
```

### Integration Testing with Database
Use in-memory KV for test isolation. Mock external HTTP calls via `std/testing/mock.ts`. Test error paths explicitly — validation errors, auth failures, 404s, 500s.

## Rules
- TypeScript strict mode — all files .ts extension.
- Router instances separate from Application — never inline routes.
- Middleware pipeline: error → logger → auth → router.
- Context state for per-request data (user, requestId).
- Oak Router prefix for route grouping — never manual path concatenation.
- Deno.env for all configuration — never hardcoded values.
- deno.json for imports — import_map.json for legacy projects.
- Always add `router.allowedMethods()` after each router.
- Never read `ctx.request.body` more than once per request.

## References
  - references/deno-runtime-guide.md — Deno Runtime Guide
  - references/oak-middleware.md — Oak Middleware
  - references/oak-performance.md — Oak Performance Optimization
  - references/oak-routing-deployment.md — Oak Routing and Deployment
  - references/oak-setup.md — Oak Setup Guide
  - references/oak-testing.md — Oak Testing
## Handoff
Hand off to `backend/universal/api-response/SKILL.md` for API response standards.
## Implementation Patterns

### Factory Pattern for Module Creation
`
function createModule(config: ModuleConfig): T {
  const dependencies = initializeDependencies(config);
  const module = new Module(dependencies);
  module.hooks.onInit();
  return module as T;
}
`

### Builder Pattern for Complex Configuration
`
class ConfigBuilder {
  private config: AppConfig = new AppConfig();
  withDatabase(url: string): ConfigBuilder { ... }
  withCache(ttl: number): ConfigBuilder { ... }
  withLogging(level: string): ConfigBuilder { ... }
  build(): AppConfig { return this.config; }
}
`

## Production Considerations

### Deployment Checklist
- [ ] Production build with optimizations enabled
- [ ] Environment variables configured per environment
- [ ] Health check endpoint responds correctly
- [ ] Error tracking and monitoring integrated
- [ ] Logging level configured (not debug in production)
- [ ] Resource limits configured
- [ ] Database migrations applied
- [ ] Static assets built and served from CDN or cache
- [ ] Feature flags toggled appropriately
- [ ] Rollback plan documented and tested

### Monitoring and Alerting
| Metric | Threshold | Severity | Action |
|--------|-----------|----------|--------|
| Error rate | > 1% | Critical | Rollback or fix |
| p95 latency | > 500ms | Warning | Profile and optimize |
| Uptime |  80% | Warning | Check for leaks |
| CPU usage | > 80% | Warning | Scale up or optimize |

## Rules
- Prefer composition over inheritance
- Favor immutable data structures
- Use dependency injection for testability
- Keep functions pure when possible — no side effects
- Fail fast with clear error messages
- Don't repeat yourself (DRY) — extract shared logic
- Keep it simple (KISS) — avoid unnecessary complexity
- You aren't gonna need it (YAGNI) — build what's required
- Separate concerns — single responsibility per module
- Code to interfaces, not implementations
- Write self-documenting code — clear names over comments
- Prefer standard library over third-party dependencies
- Handle errors explicitly — no silent failures
- Validate inputs at boundaries
- Log at appropriate levels (debug, info, warn, error)

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [j4flmao](https://github.com/j4flmao)
- **Source:** [j4flmao/agent-skills](https://github.com/j4flmao/agent-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-j4flmao-agent-skills-oak
- Seller: https://agentstack.voostack.com/s/j4flmao
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
