prisma-trpc-generator

repository·master·Indexed 20 days ago

https://github.com/omar-dulaimi/prisma-trpc-generator

A Prisma 2+ generator that automatically creates fully implemented, type-safe tRPC routers from a Prisma schema. It provides complete CRUD coverage, Zod validation, and support for middleware, authentication (Session, JWT, or Custom), tRPC Shield integration, and OpenAPI documentation. It also supports generating Postman collections and an optional Domain-Driven Design (DDD) service layer.

Tokens
11.2K
Snippets
35
Records
49
Agent score
71%

What's inside prisma-trpc-generator

  1. Understand the generated output structure

    master

    When you run the generator, it produces a structured set of files containing tRPC routers and Zod validation schemas.

    Typical Directory Layout:

    • generated/routers/index.ts: The main app router that combines all individual model routers.
    • generated/routers/helpers/createRouter.ts: A base router factory used for middleware and shield setup.
    • generated/routers/[Model].router.ts: Individual routers containing CRUD operations for a specific Prisma model (e.g., User.router.ts).
    • generated/schemas/: Contains Zod validation schemas (enabled if withZod: true is configured).
      • generated/schemas/objects/: Input type schemas.
      • generated/schemas/index.ts: Barrel exports for all schemas.
    generated/
    ├── routers/
    │   ├── index.ts              # Main app router combining all model routers
    │   ├── helpers/
    │   │   └── createRouter.ts   # Base router factory with middleware/shield setup
    │   ├── User.router.ts        # User CRUD operations
    │   └── Post.router.ts        # Post CRUD operations
    └── schemas/                  # Zod validation schemas (if withZod: true)
        ├── objects/              # Input type schemas
        ├── findManyUser.schema.ts
        ├── createOneUser.schema.ts
        └── index.ts              # Barrel exports
  2. Use authentication procedures and roles in routers

    master

    When authentication is enabled, the generator provides three types of procedures in your routers:

    1. publicProcedure: No authentication required.
    2. protectedProcedure: Requires a valid user session (ctx.user must be populated).
    3. roleProcedure(['role_name']): Requires the user to have a specific role.

    You can customize which field on the user object is checked for roles using the rolesField configuration key (defaults to "role").

    Generated Files:

    • routers/helpers/auth.ts: Contains ensureAuth(ctx) and ensureRole(ctx, roles).
    • routers/helpers/auth-strategy.ts: Contains the strategy implementation (or stubs if paths are not provided).
    • routers/helpers/createRouter.ts: Automatically wires the authMiddleware to populate ctx.user.
  3. Use Zod validation and custom constraints in Prisma

    master

    Enable Zod validation by setting "withZod": true in your config. This generates a schemas/ directory with Zod types for procedure inputs.

    Customizing Validation with Prisma Comments: You can inject specific Zod constraints directly into your Prisma schema using triple-slash comments (///).

    Example:

    model User {
      id    Int     @id @default(autoincrement()) /// @zod.number.int()
      email String  @unique /// @zod.string.email()
      name  String? /// @zod.string.min(1).max(100)
    }

    This results in a generated Zod schema like:

    export const UserCreateInput = z.object({
      id: z.number().int(),
      email: z.string().email(),
      name: z.string().min(1).max(100).nullish(),
    });
    model User {
      id    Int     @id @default(autoincrement()) /// @zod.number.int()
      email String  @unique /// @zod.string.email()
      name  String? /// @zod.string.min(1).max(100)
      age   Int?    /// @zod.number.int().min(0).max(120)
    }
    
    model Post {
      id        Int      @id @default(autoincrement()) /// @zod.number.int()
      title     String   /// @zod.string.min(1).max(255, { message: "Title must be shorter than 256 characters" })
      content   String?  /// @zod.string.max(10000)
      published Boolean  @default(false)
    
      author   User? @relation(fields: [authorId], references: [id])
      authorId Int?
    }
  4. Configure Authentication (Session, JWT, or Custom)

    master

    Enable authentication by setting the auth key in your configuration.

    Supported Strategies:

    • session
    • jwt
    • custom

    Configuration Object Shape:

    "auth": {
      "strategy": "jwt",
      "rolesField": "role",
      "jwt": { "secret": "..." },
      "session": { "..." },
      "custom": { "..." }
    }

    Generated Files:

    • routers/helpers/auth-strategy.ts: Contains stubs and a default HS256 JWT verifier.
    • routers/helpers/auth.ts: Provides ensureAuth and ensureRole helpers.
    • createRouter.ts: Automatically wires authMiddleware, publicProcedure, protectedProcedure, and roleProcedure(roles).
  5. Minimal setup for prisma-trpc-generator

    master

    To perform a minimal setup, add the generator block to your Prisma schema and point it to a JSON configuration file. Note that both output and config paths are resolved relative to the schema file.

    1. Add the generator to schema.prisma.
    2. Create a trpc.config.json file.
    3. Enable "strict": true in your tsconfig.json.
    4. Run npx prisma generate.
    generator trpc {
      provider = "prisma-trpc-generator"
      output   = "./generated"
      config   = "./trpc.config.json"
    }
  6. Skip models during generation

    master

    To prevent the generator from creating routers or schemas for specific models (e.g., internal logs or metadata tables), use the @@Gen.model(hide: true) attribute in your schema.prisma file.

    /// @@Gen.model(hide: true)
    model InternalLog {
      id        Int      @id @default(autoincrement())
      message   String
      createdAt DateTime @default(now())
    }
  7. Configure Prisma 7 for the generator

    master

    To use the generator with Prisma 7, follow these steps:

    1. Create prisma.config.ts at your repository root to define your schema, migrations, and datasource.
    2. Update your generator client block in schema.prisma to ensure the client is outputted to the correct location.
    3. Set DATABASE_URL in your .env file and ensure your PrismaClient is instantiated with the appropriate database adapter (e.g., @prisma/adapter-pg for Postgres).
    // prisma.config.ts
    import 'dotenv/config';
    import { defineConfig, env } from 'prisma/config';
    
    export default defineConfig({
      schema: 'prisma/schema.prisma',
      migrations: {
        path: 'prisma/migrations',
        seed: 'tsx prisma/seed.ts',
      },
      datasource: {
        url: env('DATABASE_URL'),
      },
    });
    // schema.prisma
    generator client {
      provider = "prisma-client"
      output   = "../node_modules/.prisma/client"
    }
  8. Enable authentication in Prisma tRPC Generator

    master

    To enable authentication, add the auth key to your JSON configuration.

    Setting "auth": true enables protectedProcedure and roleProcedure using the default session strategy.

    For more control, provide an object specifying the strategy ("session", "jwt", or "custom") and an optional rolesField to define which field on the user object is used for role-based access control.

    {
      "auth": {
        "strategy": "session",
        "rolesField": "role"
      }
    }
  9. Configure the generator via trpc.config.json

    master

    Configuration is unified via a single JSON file. The generator block in your Prisma schema should only specify output and config to avoid warnings and deprecation issues.

    Key Configuration Options:

    • showModelNameInProcedure (boolean): Controls if model names are appended to procedures (e.g., createOneUser). Defaults to true. Set to false for cleaner names like createOne when using per-model routers.
    • withZod (boolean): Enables Zod validation.
    • withMiddleware (boolean | string): Enables middleware scaffolding or points to a custom path.
    • withShield (boolean | string): Enables tRPC Shield integration.
    • contextPath (string): Path to your context file.
    • trpcOptionsPath (string): Path to your tRPC options.
    • dateTimeStrategy (string): Controls DateTime validation ("date", "coerce", or "isoString").
    • openapi (boolean | object): Enables OpenAPI support.
    • postman (boolean | object): Enables Postman collection generation.
    {
      "withZod": true,
      "withMiddleware": true,
      "withShield": "./shield",
      "contextPath": "./context",
      "trpcOptionsPath": "./trpcOptions",
      "dateTimeStrategy": "date",
      "withMeta": false,
      "postman": true,
      "postmanExamples": "skeleton",
      "openapi": true,
      "withRequestId": false,
      "withLogging": false,
      "withServices": false,
      "showModelNameInProcedure": true
    }
  10. How the generator handles Zod schemas and Services

    master

    The generator supports advanced patterns for type safety and business logic delegation:

    Zod Schema Integration

    If config.withZod is enabled, the generator looks for existing .schema.ts files in the schemas directory (e.g., User.schema.ts). It will only generate tRPC procedures for operations where a corresponding schema file is found. This ensures that every generated procedure has a valid Zod input validator.

    Service Delegation

    If config.withServices is enabled, the generator assumes you are using a service layer. It will automatically add an import for makeServices in your generated router files, allowing the router to delegate business logic to your service implementations.

  11. Configure ServiceStyle for generated services

    master

    The ServiceStyle type determines the architectural pattern used for the generated service layer. You can choose between three styles:

    • 'class': Generates services as standard TypeScript classes.
    • 'factory': Generates services using a factory function pattern.
    • 'plain': Generates services as plain objects.

    This setting is configured within the ServicesConfig object.

    export type ServiceStyle = 'class' | 'factory' | 'plain';