npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

prisma-generator-express

v1.16.6

Published

Prisma generator of Express CRUD API

Downloads

119

Readme

Prisma Generator Express

npm version npm HitCount Coverage Status npm

This tool helps you quickly create API endpoints in your Express app using your Prisma models.

When you run npx prisma generate, it automatically creates two things:

  • Exposes Prisma API to clients - all operations with database is available, including all relationships at any depth.
  • Service functions that you can import into your Express routes. By default, these functions handle CRUD operations and output validation. This behavior can be controlled.
  • Router generator function that lets you select which routes to add to the application and which middlewares to apply.

Table of Contents

Installation

Using npm:

 npm install prisma-generator-express

Using yarn:

 yarn add prisma-generator-express

Basic usage

  • Include this generator in your schema.prisma file:
generator express {
  provider = "prisma-generator-express"
}
  • Generate your middleware functions by running:
  npx prisma generate
  • Attach Prisma instance
import { PrismaClient } from '@prisma/client'
import express from 'express'

const prisma = new PrismaClient()
const app = express()

app.use(express.json()) // for parsing application/json

// Attach Prisma to every request
app.use((req, res, next) => {
  req.prisma = prisma
  next()
})
  • Here’s how you can use a generated function in your Express app:
import { UserFindUnique } from './generated/api/UserFindUnique' // Adjust the path as necessary
import { FindUniqueUserSchema } from './prisma-zod-generator/schemas/FindUniqueUser.schema' // Adjust the path as necessary
import { FindUniqueUserSchemaOutput } from './prisma-zod-generator/schemas/FindUniqueUserOutput.schema' // Adjust the path as necessary

// move this to /helpers
export function validateQuery(schema: ZodSchema) {
  return async (req: Request, res: Response, next: NextFunction) => {
    try {
      req.query = schema.parse(req.query)
      next()
    } catch (error) {
      res.status(400).json({
        error: 'Input Validation failed',
        details: error.errors,
      })
    }
  }
}

app.get(
  '/user/:id',
  validateQuery(FindUniqueUserSchema),
  async (req, res, next) => {
    // Attach generated Zod schema for output validation
    req.outputValidation = FindUniqueUserOutput

    // Use the generated middleware to handle the request
    await UserFindUnique(req, res, next)
  },
)

The UserFindUnique function will fetch the user details from the database, validate the output with Zod, and handle the API response.

Router generator usage

The library will create functions to generate routers per each model in schema. Each route can accept middleware that will be injected right before generated handler is invoked. You can use it to modify/remove/validate request payload. The output validation can be also attached to req object on this step.

import express, { json } from 'express'
import type { Response, Request, NextFunction, RequestHandler } from 'express'

import { PrismaClient } from '../prisma/generated/client'
import { UserAccountRouter } from '../prisma/generated/express/UserAccount'
import { RouteConfig } from '~prisma/generated/express/routeConfig'
import { UserAccountFindFirstSchema } from '../prisma/generated/prisma-zod-generator/schemas'

const app = express()

const prisma = new PrismaClient()

/**
 * Middleware to attach Prisma client instance to the request object.
 * This ensures that Prisma client is available in all subsequent middleware and route handlers.
 */
const addPrisma: RequestHandler = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  req.prisma = prisma
  next()
}

/**
 * Run context-related operations or modify `req` properties to control the behavior of the route
 */
const beforeFindFirst: RequestHandler = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  req.passToNext = true
  next()
}

/**
 * if `req.passToNext` is true, then the result of generated middleware
 * will be available in req.locals?.data for modifications
 */
const afterFindFirst: RequestHandler = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  console.log('req.locals?.data :>> ', req.locals?.data)
  next()
}

/**
 * For generated route the middleware order will be as follows:
 * 1. Query parser (kicks in for GET requests)
 * 2. Custom middlewares: config.{method}.before[]
 * 3. Input validator middleware (Optional): config.{method}.input. For GET request validates `req.query`, for others - `req.body`
 * 4. Generated middleware
 * 5. Output validator middleware: config.{method}.input
 * 6. Custom middlewares: config.{method}.after[] (not available if req.passToNext is falsy)
 */
const userAccounRouterConfig: RouteConfig<RequestHandler> = {
  FindFirst: {
    before: [beforeFindFirst],
    after: [afterFindFirst],
    input: {
      schema: UserAccountFindFirstSchema, // make sure you set `isGenerateSelect = true` in prisma-zod-generator
      allow: [
        'select.id',
        'select.full_name',
        'select.emailAddress',
        'select.orders[].ProductName',
        'select.orders[].quantity',
        'where.id',
        'where.createdAt',
      ],
    },
  },
  addModelPrefix: true,
  enableAll: true,
  customUrlPrefix: '/v1',
}

app.use(addPrisma)
app.use(UserAccountRouter(userAccounRouterConfig))

app.listen(3000, () => {
  console.log('Server is running on http://localhost:3000')
})

Request Object Properties

The following properties can be attached to the req object to control the behavior of generated middleware:

| Property | Type | Description | | ---------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------- | | prisma | PrismaClient | An instance of PrismaClient that allows the middleware to interact with your database. | | passToNext | boolean | Optional, if true - the result of a Prisma request will be passed to the next middleware as if (req.locals) req.locals.data | | outputValidation | ZodTypeAny | (Optional) A Zod schema used to validate the data returned from the Prisma query before sending it to the client. |

Router Schema

| Function | Method | URL | | ------------ | -------- | ------------ | | findUnique | GET | /:id | | findFirst | GET | /first | | findMany | GET | / | | aggregate | GET | /aggregate | | count | GET | /count | | groupBy | GET | /groupby | | create | POST | / | | createMany | POST | /many | | update | PUT | / | | updateMany | PUT | /many | | upsert | PATCH | / | | delete | DELETE | / | | deleteMany | DELETE | /many |

Skip generation

/// generator off
model UserAccount {
  ID           Int         @id @default(autoincrement())
  full_name    String
  emailAddress String      @unique
  createdAt    DateTime    @default(now())
  orders       orderItem[]
}

Helper functions

createValidatorMiddleware(validatorOptions: ValidatorOptions)

Simple wrapper that internally uses allow or forbid logic for filtering incoming queries and data payloads. Helps to make sure that schemas from prisma-zod-generator is not too permissive.

interface ValidatorOptions {
  schema: ZodSchema<any>
  allowedPaths?: string[] // Fobids all except allowed. For example [`where.user.id`, `select.id`], all other provided inputs will throw an error
  forbiddenPaths?: string[] // Similar, but allows all, except forbidden
  target?: 'body' | 'query'
}

encodeQueryParams(params: Params)

It can be used on the frontend to encode Prisma-compatible queries. Alternatively qs can be used, but it probably won't work with OR: [{ blah: false }, { blah: null }] or some other edge cases.

type RecursiveUrlParams = {
  [key: string]: RecursiveUrlParams | string | boolean | unknown
}
type Params = Record<string, RecursiveUrlParams | string>

parseQueryParams(params: QueryParams)

type QueryParams = string | ParsedQs | string[] | ParsedQs[] | undefined

Recursively converts strings "true", "false", "null", and "number" into correct formats.

allow( schema: T, allowedPaths: string[] ): ZodEffects<T, any, any>

Accepts schema and ['array.of.allowed.paths']. Throws an error if provided something that doesn't fit allowed schema.

forbid( schema: T, forbiddenPaths: string[] ): ZodEffects<T, any, any>

Same as allow but works in opposite way.


Credits: