prisma-nexus-api v0.0.26
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 generateThis 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.
1 year ago
1 year ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago