Skip to content

Code Generation ​

Automate boilerplate code creation with CurisJS generators.

Overview ​

The CurisJS CLI includes powerful code generators that help you quickly scaffold models, controllers, middleware, and more while following best practices.

Model Generator ​

Basic Model ​

bash
curis generate model User

Generates:

typescript
// src/app/models/User.ts
import { Model } from '@curisjs/db';

export class User extends Model {
  static tableName = 'users';
  static timestamps = true;
  
  id!: number;
  createdAt!: Date;
  updatedAt!: Date;
}

With Custom Options ​

bash
curis g model Post --table blog_posts --soft-delete

Generates:

typescript
// src/app/models/Post.ts
import { Model } from '@curisjs/db';

export class Post extends Model {
  static tableName = 'blog_posts';
  static timestamps = true;
  static softDelete = true;
  
  id!: number;
  deletedAt?: Date;
  createdAt!: Date;
  updatedAt!: Date;
}

Controller Generator ​

Basic Controller ​

bash
curis generate controller UserController

Generates:

typescript
// src/app/controllers/UserController.ts
import { Context } from '@curisjs/core';

export class UserController {
  static async index(ctx: Context) {
    // List all users
  }
  
  static async show(ctx: Context) {
    // Show single user
  }
}

Resource Controller ​

bash
curis g controller UserController --resource

Generates a full CRUD controller:

typescript
// src/app/controllers/UserController.ts
import { Context, json } from '@curisjs/core';
import { User } from '../models/User';

export class UserController {
  /**
   * List all users
   * GET /users
   */
  static async index(ctx: Context) {
    const users = await User.findMany();
    return json({ users });
  }
  
  /**
   * Show user details
   * GET /users/:id
   */
  static async show(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    return json({ user });
  }
  
  /**
   * Create new user
   * POST /users
   */
  static async store(ctx: Context) {
    const data = await ctx.request.json();
    const user = await User.create(data);
    return json({ user }, { status: 201 });
  }
  
  /**
   * Update user
   * PUT /users/:id
   */
  static async update(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    const data = await ctx.request.json();
    await user.update(data);
    
    return json({ user });
  }
  
  /**
   * Delete user
   * DELETE /users/:id
   */
  static async destroy(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    await user.delete();
    
    return new Response(null, { status: 204 });
  }
}

API Controller ​

bash
curis g controller UserController --api

Generates an API-focused controller with validation:

typescript
// src/app/controllers/UserController.ts
import { Context, json, z } from '@curisjs/core';
import { User } from '../models/User';

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

const updateUserSchema = createUserSchema.partial();

export class UserController {
  static async index(ctx: Context) {
    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 json({
      data: users,
      meta: {
        page,
        limit,
        total,
        totalPages: Math.ceil(total / limit),
      },
    });
  }
  
  static async show(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    return json({ data: user });
  }
  
  static async store(ctx: Context) {
    const body = await ctx.request.json();
    const result = createUserSchema.safeParse(body);
    
    if (!result.success) {
      return json({
        error: 'Validation failed',
        issues: result.error.issues,
      }, { status: 422 });
    }
    
    const user = await User.create(result.data);
    return json({ data: user }, { status: 201 });
  }
  
  static async update(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    const body = await ctx.request.json();
    const result = updateUserSchema.safeParse(body);
    
    if (!result.success) {
      return json({
        error: 'Validation failed',
        issues: result.error.issues,
      }, { status: 422 });
    }
    
    await user.update(result.data);
    return json({ data: user });
  }
  
  static async destroy(ctx: Context) {
    const user = await User.findById(ctx.params.id);
    
    if (!user) {
      return json({ error: 'User not found' }, { status: 404 });
    }
    
    await user.delete();
    return new Response(null, { status: 204 });
  }
}

Middleware Generator ​

bash
curis generate middleware auth

Generates:

typescript
// src/app/middleware/auth.ts
import { Context, Middleware, Next, json } from '@curisjs/core';

export const auth: Middleware = async (ctx: Context, next: Next) => {
  const token = ctx.request.headers.get('Authorization');
  
  if (!token) {
    return json({ error: 'Unauthorized' }, { status: 401 });
  }
  
  try {
    // Verify token
    const user = await verifyToken(token);
    ctx.state.user = user;
    
    await next();
  } catch (error) {
    return json({ error: 'Invalid token' }, { status: 401 });
  }
};

Migration Generator ​

bash
curis generate migration CreateUsersTable

Generates:

typescript
// src/database/migrations/2024_11_17_100000_create_users_table.ts
import { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
  return knex.schema.createTable('users', (table) => {
    table.increments('id').primary();
    table.string('name').notNullable();
    table.string('email').notNullable().unique();
    table.timestamps(true, true);
  });
}

export async function down(knex: Knex): Promise<void> {
  return knex.schema.dropTable('users');
}

Validator Generator ​

bash
curis generate validator UserValidator

Generates:

typescript
// src/app/validators/UserValidator.ts
import { z } from '@curisjs/core';

export const createUserSchema = z.object({
  name: z.string().min(2).max(100),
  email: z.string().email(),
  password: z.string().min(8),
});

export const updateUserSchema = createUserSchema.partial();

export const userIdSchema = z.object({
  id: z.string().uuid(),
});

Service Generator ​

bash
curis generate service EmailService

Generates:

typescript
// src/app/services/EmailService.ts
export class EmailService {
  static async send(to: string, subject: string, body: string) {
    // Email sending logic
  }
  
  static async sendWelcome(email: string, name: string) {
    return this.send(
      email,
      'Welcome!',
      `Hello ${name}, welcome to our platform!`
    );
  }
}

Complete Example Workflow ​

bash
# 1. Create a new project
curis new blog

# 2. Navigate to project
cd blog

# 3. Generate Post model
curis g model Post --soft-delete

# 4. Generate migration
curis g migration CreatePostsTable

# 5. Generate Post controller
curis g controller PostController --resource

# 6. Generate validators
curis g validator PostValidator

# 7. Generate auth middleware
curis g middleware auth

# 8. Run migrations
curis db:migrate

# 9. Start development
curis dev

Customizing Templates ​

You can customize generator templates by creating a templates/ directory in your project:

my-app/
├── templates/
│   ├── model.ts.ejs
│   ├── controller.ts.ejs
│   └── middleware.ts.ejs
└── src/

The CLI will use your custom templates instead of the defaults.

Tips ​

  1. Use descriptive names - UserController is better than UC
  2. Follow conventions - Models are singular, tables are plural
  3. Generate early - It's easier to modify generated code than write from scratch
  4. Review generated code - Always check the output before using
  5. Customize as needed - Generated code is a starting point

Next Steps ​

Released under the MIT License.