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-nexus-api

v0.0.25

Published

Tool for creating api's easier using prisma and nexus

Downloads

194

Readme

prisma-nexus-api

The intention of this project is the following:

  1. Single package with prisma generator and getNexusTypes helper fuction.
  2. Using prisma generator, a ApiConfig type is generated based on db schema. The generated types are to help with auto completion/configuration.
  3. The function getNexusTypes takes a options object that contains this ApiConfig.
  4. getNexusTypes returns all needed nexus types based on the ApiConfig (queries, mutations, inputs, outputs, and models.
  5. Users can use the nexus extendType to extend the types generated at runtime.

See the /packages/usage for an example

Prisma Generator Usage

To use the prisma generator, add it to your prisma schema file.

generator api {
  provider = "prisma-nexus-api"
}

You can then run

npx prisma generate

This will generate all typing needed for your api.

The generator can also have a schemaPath property configured. The default schema path is ./prisma/schema.prisma.

Plugin Usage

To use getNexusTypes, call it with your ApiConfig. Then pass these types to nexus.

Note you must use PrismaSelect from @paljs/plugins. This adds functionality to convert graphql info into a prisma select statement used by our operations.

import { makeSchema } from 'nexus'
import { getNexusTypes, ApiConfig } from 'prisma-nexus-api'
import { applyMiddleware } from 'graphql-middleware'
import { PrismaSelect } from '@paljs/plugins'
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

const apiConfig:ApiConfig = {
  prisma,
  data: {
    all: {}
  }
}

const getSchema = async () => {
  const types = await getNexusTypes({
    apiConfig
  })

  const schema = makeSchema({
    types,
    outputs: {
      schema: path.join(__dirname, './generated/nexus/schema.graphql'),
      typegen: path.join(__dirname, './generated/nexus/nexus.ts')
    }
  })

  const prismaSelect = async (resolve: any, root:any, args:any, ctx: any, info:any) => {
    ctx.select = new PrismaSelect(info).value
    return resolve(root, args, ctx, info)
  }

  return applyMiddleware(schema, prismaSelect)
}

Configruation

You must pass your prismaClient to ApiConfig. You can optionally pass a PubSubEngine for publishing subscription events. See graphql-subscriptions for more on the PubSubEngine.

A ApiConfig can specify a ModelConfiguration for each model in your db. The prisma generator will generate typescript typing to help with auto completion of your apiConfiguration object. There is also a all ModelConfiguration which will be applied to all models.

const apiConfig:ApiConfig = {
    prisma: PrismaClient,
    pubsub?: PubSubEngine,
    data: {
        all: ModelConfiguration,
        User: ModelConfiguration
        Car: ModelConfiguration,
        ...etc
    }
}

A ModelConfiguration can then have configuration for each supported operation type, create, read, update, upsert, delete.

export type ModelConfiguration = {
    removeFromSchema?: boolean
    removedFields?: string[]
    removeNestedCreate?: boolean
    removeNestedUpdate?: boolean
    disableAllOperations?: boolean
    create?: ModelCreateConfiguration
    read?: ModelReadConfiguration
    update?: ModelUpdateConfiguration
    upsert?: ModelUpsertConfiguration
    delete?: ModelDeleteConfiguration
}

export type ModelCreateConfiguration = {
    disableAll?: boolean
    removedFields?: string[]
    createOneOverride?: OperationOverride
}

export type ModelReadConfiguration = {
    disableAll?: boolean
    disableAggregate?: boolean
    disableFindCount?: boolean
    disableFindFirst?: boolean
    disableFindMany?: boolean
    disableFindUnique?: boolean
    removedFields?: string[]
    aggregateOverride?: OperationOverride
    findCountOverride?: OperationOverride
    findFirstOverride?: OperationOverride
    findManyOverride?: OperationOverride
    findUniqueOverride?: OperationOverride
}

export type ModelUpdateConfiguration = {
    disableAll?: boolean
    disableUpdateOne?: boolean
    disableUpdateMany?: boolean
    removedFields?: string[]
    updateOneOverride?: OperationOverride
    updateManyOverride?: OperationOverride
}

export type ModelUpsertConfiguration = {
    disableAll?: boolean
    upsertOneOverride?: OperationOverride
}

export type ModelDeleteConfiguration = {
    disableAll?: boolean
    disableDeleteOne?: boolean
    disableDeleteMany?: boolean
    deleteOneOverride?: OperationOverride
    deleteManyOverride?: OperationOverride
}

Removing fields from the create configuration removes fields from the exposed create input. Removing fields from the update configuration removes fields from the exposed update input. Removing fields from the read configuration removes the fields from the graphql outputs.

You can disable any specific operation, disableAggregate, disableFindCount etc

Using disableAll will disable all operations in that grouping. Ex. ModelDeleteConfiguration disableAll will disable both disableDeleteOne and deleteManyOverride. Using the top level disableAllOperations will disable all operations for that model.

removeFromSchema will remove the model from the schema and disableAllOperations. You can disableAllOperations but not remove the schema to allow you to use the model, input, and output types for your own custom operations.

Override

The override functions are a hook you can use for the incoming operation. These allow you to add custom validation, permission checks, or custom logic. If you don't need your validation/authorized checks in this level of scope I suggest using graphql-shield

Note the prisma function will no longer be called by default when using the override hook.

Your override function will recieve the following parameter.

export type OperationOverrideOptions<ParamsType, ContextType> = {
    // car, user, etc
    modelName:string
    // create, update, etc
    prismaOperation:string
    prismaParams: ParamsType
    ctx: ContextType
    apiConfig: ApiConfig
}

The modelName and prismaOperation are passed to allow you to use generic handlers for multiple operations. Ex.

export const operationFilterForOrganizationOverride = (options:OperationOverrideOptions<any, any>) => {
  const {
    modelName,
    prismaOperation,
    prismaParams,
    ctx
  } = options
  const session = ctx.session

  options.prismaParams.where = {
    ...options.prismaParams.where,
    organizationId: session.organizationId
  }

  return (ctx.prisma as any)[modelName][prismaOperation](options.prismaParams)
}

Helper Functions

There are a few helper functions exposed. createAndNotify, updateAndNotify, updateManyAndNotify, etc. These will run their mutations and also publish the event to the subscription pubsub if one is configured. These functions take the override params with an additional option to configure your event.

export interface CreateAndNotifyOptions extends OperationOverrideOptions {
  createEvent?: string
}

By default these events are modelName_CREATED, car_CREATED, user_UPDATED, book_DELETED etc.