Skip to content

Examples ​

Learn by example with practical CurisJS applications.

Overview ​

This section contains complete, working examples of CurisJS applications. Each example demonstrates specific features and best practices.

Quick Examples ​

Hello World ​

The simplest CurisJS application:

typescript
import { Application } from '@curisjs/core';

const app = new Application();

app.get('/', (ctx) => {
  return ctx.json({ message: 'Hello World' });
});

app.listen({ port: 3000 });

JSON API ​

A basic JSON API with multiple routes:

typescript
import { Application } from '@curisjs/core';

const app = new Application();

// List items
app.get('/api/items', async (ctx) => {
  const items = await db.items.findMany();
  return ctx.json({ items });
});

// Get single item
app.get('/api/items/:id', async (ctx) => {
  const item = await db.items.findById(ctx.params.id);
  
  if (!item) {
    return ctx.json({ error: 'Not found' }, { status: 404 });
  }
  
  return ctx.json({ item });
});

// Create item
app.post('/api/items', async (ctx) => {
  const data = await ctx.request.json();
  const item = await db.items.create(data);
  return ctx.json({ item }, { status: 201 });
});

app.listen({ port: 3000 });

With Middleware ​

Using middleware for logging and error handling:

typescript
import { Application, logger, cors } from '@curisjs/core';

const app = new Application();

// Global middleware
app.use(logger());
app.use(cors());

// Error handling
app.use(async (ctx, next) => {
  try {
    await next();
  } catch (error) {
    console.error(error);
    return ctx.json(
      { error: 'Internal Server Error' },
      { status: 500 }
    );
  }
});

// Routes
app.get('/api/users', async (ctx) => {
  const users = await getUsers();
  return ctx.json({ users });
});

app.listen({ port: 3000 });

With Validation ​

Input validation using schemas:

typescript
import { Application, z } from '@curisjs/core';

const app = new Application();

const createUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  age: z.number().min(18).max(120),
});

app.post('/api/users', async (ctx) => {
  const body = await ctx.request.json();
  
  // Validate input
  const result = createUserSchema.safeParse(body);
  
  if (!result.success) {
    return ctx.json(
      { 
        error: 'Validation failed',
        issues: result.error.issues 
      },
      { status: 422 }
    );
  }
  
  const user = await createUser(result.data);
  return ctx.json({ user }, { status: 201 });
});

app.listen({ port: 3000 });

Complete Applications ​

RESTful API ​

A complete REST API with CRUD operations:

typescript
import { Application, z } from '@curisjs/core';
import { User } from './models/User';

const app = new Application();

// Schemas
const createUserSchema = z.object({
  name: z.string().min(2),
  email: z.string().email(),
});

const updateUserSchema = createUserSchema.partial();

// List users
app.get('/api/users', async (ctx) => {
  const page = parseInt(ctx.url.searchParams.get('page') || '1');
  const limit = parseInt(ctx.url.searchParams.get('limit') || '10');
  
  const users = await User.findMany({
    limit,
    offset: (page - 1) * limit,
  });
  
  const total = await User.count();
  
  return ctx.json({
    data: users,
    meta: {
      page,
      limit,
      total,
      totalPages: Math.ceil(total / limit),
    },
  });
});

// Get user
app.get('/api/users/:id', async (ctx) => {
  const user = await User.findById(ctx.params.id);
  
  if (!user) {
    return ctx.json({ error: 'User not found' }, { status: 404 });
  }
  
  return ctx.json({ data: user });
});

// Create user
app.post('/api/users', async (ctx) => {
  const body = await ctx.request.json();
  const result = createUserSchema.safeParse(body);
  
  if (!result.success) {
    return ctx.json({
      error: 'Validation failed',
      issues: result.error.issues,
    }, { status: 422 });
  }
  
  const user = await User.create(result.data);
  return ctx.json({ data: user }, { status: 201 });
});

// Update user
app.put('/api/users/:id', async (ctx) => {
  const user = await User.findById(ctx.params.id);
  
  if (!user) {
    return ctx.json({ error: 'User not found' }, { status: 404 });
  }
  
  const body = await ctx.request.json();
  const result = updateUserSchema.safeParse(body);
  
  if (!result.success) {
    return ctx.json({
      error: 'Validation failed',
      issues: result.error.issues,
    }, { status: 422 });
  }
  
  await user.update(result.data);
  return ctx.json({ data: user });
});

// Delete user
app.delete('/api/users/:id', async (ctx) => {
  const user = await User.findById(ctx.params.id);
  
  if (!user) {
    return ctx.json({ error: 'User not found' }, { status: 404 });
  }
  
  await user.delete();
  return new Response(null, { status: 204 });
});

app.listen({ port: 3000 });

Authentication API ​

API with authentication and protected routes:

typescript
import { Application, z } from '@curisjs/core';
import { sign, verify } from 'jsonwebtoken';

const app = new Application();

const JWT_SECRET = process.env.JWT_SECRET || 'secret';

// Auth middleware
const auth = async (ctx, next) => {
  const token = ctx.request.headers.get('Authorization')?.replace('Bearer ', '');
  
  if (!token) {
    return ctx.json({ error: 'Unauthorized' }, { status: 401 });
  }
  
  try {
    const payload = verify(token, JWT_SECRET);
    ctx.state.user = payload;
    await next();
  } catch (error) {
    return ctx.json({ error: 'Invalid token' }, { status: 401 });
  }
};

// Public routes
app.post('/api/register', async (ctx) => {
  const { email, password } = await ctx.request.json();
  
  // Hash password and create user
  const user = await createUser({ email, password });
  
  const token = sign({ userId: user.id }, JWT_SECRET, { expiresIn: '7d' });
  
  return ctx.json({ user, token }, { status: 201 });
});

app.post('/api/login', async (ctx) => {
  const { email, password } = await ctx.request.json();
  
  const user = await findUserByCredentials(email, password);
  
  if (!user) {
    return ctx.json({ error: 'Invalid credentials' }, { status: 401 });
  }
  
  const token = sign({ userId: user.id }, JWT_SECRET, { expiresIn: '7d' });
  
  return ctx.json({ user, token });
});

// Protected routes
app.get('/api/profile', auth, async (ctx) => {
  const user = await User.findById(ctx.state.user.userId);
  return ctx.json({ user });
});

app.put('/api/profile', auth, async (ctx) => {
  const user = await User.findById(ctx.state.user.userId);
  const updates = await ctx.request.json();
  
  await user.update(updates);
  return ctx.json({ user });
});

app.listen({ port: 3000 });

File Upload API ​

Handling file uploads:

typescript
import { Application } from '@curisjs/core';
import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';

const app = new Application();

app.post('/api/upload', async (ctx) => {
  const formData = await ctx.request.formData();
  const file = formData.get('file') as File;
  
  if (!file) {
    return ctx.json({ error: 'No file provided' }, { status: 400 });
  }
  
  // Validate file type
  if (!file.type.startsWith('image/')) {
    return ctx.json({ error: 'Only images allowed' }, { status: 400 });
  }
  
  // Validate file size (5MB max)
  if (file.size > 5 * 1024 * 1024) {
    return ctx.json({ error: 'File too large' }, { status: 400 });
  }
  
  // Save file
  const filename = `${Date.now()}-${file.name}`;
  const filepath = join('uploads', filename);
  
  const buffer = await file.arrayBuffer();
  await writeFile(filepath, Buffer.from(buffer));
  
  return ctx.json({
    filename,
    size: file.size,
    type: file.type,
    url: `/uploads/${filename}`,
  }, { status: 201 });
});

// Serve uploaded files
app.get('/uploads/:filename', async (ctx) => {
  const filepath = join('uploads', ctx.params.filename);
  
  try {
    const file = await Bun.file(filepath);
    return new Response(file);
  } catch {
    return ctx.json({ error: 'File not found' }, { status: 404 });
  }
});

app.listen({ port: 3000 });

Runtime-Specific Examples ​

Node.js Server ​

typescript
import { Application } from '@curisjs/core';
import { nodeAdapter } from '@curisjs/core/adapters';
import { createServer } from 'node:http';

const app = new Application();

app.get('/', (ctx) => ctx.json({ runtime: 'Node.js' }));

const server = createServer(nodeAdapter(app));
server.listen(3000);

Bun Server ​

typescript
import { Application } from '@curisjs/core';

const app = new Application();

app.get('/', (ctx) => ctx.json({ runtime: 'Bun' }));

Bun.serve({
  port: 3000,
  fetch: app.fetch,
});

Deno Server ​

typescript
import { Application } from '@curisjs/core';

const app = new Application();

app.get('/', (ctx) => ctx.json({ runtime: 'Deno' }));

Deno.serve({ port: 3000 }, app.fetch);

Cloudflare Workers ​

typescript
import { Application } from '@curisjs/core';

const app = new Application();

app.get('/', (ctx) => ctx.json({ runtime: 'Cloudflare Workers' }));

export default {
  fetch: app.fetch,
};

Source Code ​

Full source code for these examples is available in the repository:

Next Steps ​

Released under the MIT License.