About
This plugin integrates Prisma into Nexus. It gives you an API to project fields from models defined in your Prisma schema into your GraphQL API. It also gives you an API to build GraphQL root fields that allow your API clients to query and mutate data.
Note: You may also use nexus-prisma
, a newer API for integrating Nexus and Prisma.
Installation
$npm install nexus-plugin-prisma @prisma/client$npm install -D prisma
Usage
- Import
nexusPrisma
fromnexus-plugin-prisma
- Create and configure it if needed (usually not)
- Pass into
Nexus.makeSchema
plugins
array
Note: If you're looking for CRUD capabilities, you must enable the
experimentalCRUD
option.
You can find runnable examples in the repo examples folder.
Example
1import { nexusPrisma } from 'nexus-plugin-prisma'2import { makeSchema } from 'nexus'3import * as types from './types'45const schema = makeSchema({6 types,7 plugins: [nexusPrisma()],8})
Configuration
Note that, in most cases, you should not need to configure anything.
1type Options = {2 /**3 * Enable experimental CRUD capabilities.4 * Add a `t.crud` method in your definition block to generate CRUD resolvers in your `Query` and `Mutation` GraphQL Object Type.5 *6 * @default false7 */89 experimentalCRUD?: boolean10 /**11 * nexus-plugin-prisma will call this to get a reference to an instance of the Prisma Client.12 * The function is passed the context object. Typically a Prisma Client instance will13 * be available on the context to support your custom resolvers. Therefore the14 * default getter returns `ctx.prisma`.15 */16 prismaClient?: PrismaClientFetcher17 /**18 * Same purpose as for that used in `NexusSchema.makeSchema`. Follows the same rules19 * and permits the same environment variables.20 */21 shouldGenerateArtifacts?: boolean2223 inputs?: {24 /**25 * What is the path to the Prisma Client package? By default looks in26 * `node_modules/@prisma/client`. This is needed in order to read your Prisma27 * schema AST and Prisma Client CRUD info from the generated Prisma Client package.28 */29 prismaClient?: string30 }31 outputs?: {32 /**33 * Where should typegen be put on disk? By default emits into `node_modules/@types`.34 */35 typegen?: string36 }37 computedInputs?: GlobalComputedInputs3839 /**40 * GraphQL doesn't support union types. The plugin has to apply a flattening heuristic and pick by default the broadest member of the union.41 * On update and upsert, the broadest member is the atomic operation, which is not ideal in many cases.42 *43 * @default true44 */45 atomicOperations?: boolean46}
Getting started
There are two ways you can start with the Prisma plugin. Either from scratch, or using an existing database.
From scratch
Create a
schema.prisma
file1//schema.prisma23generator prisma_client {4 provider = "prisma-client-js"5}67model User {8 id Int @id @default(autoincrement())9 name String10}Add a datasource to your schema. We recommend you use Postgres but MySQL and SQLite are also supported.
To add your datasource, simply copy/paste one of the block below at the top of your
schema.prisma
fileNote: You can also pass the database credentials via a
.env
file. Read more about it hereUsing PostgreSQL:
1//schema.prisma23datasource db {4 provider = "postgres"5 url = "postgresql://USER:PASSWORD@localhost:5432/DATABASE"6}Using MySQL:
1//schema.prisma23datasource db {4 provider = "mysql"5 url = "mysql://USER:PASSWORD@localhost:3306/DATABASE"6}Using SQLite:
1//schema.prisma23datasource db {4 provider = "sqlite"5 url = "file:./dev.db"6}Create a migration from changes in Prisma schema and run the migration
$npx prisma migrate dev
You're ready to start working!
From an existing database
When starting from an existing database, you should use Prisma's introspection feature.
- Create a
schema.prisma
file.
Create a schema.prisma
file and add your database credentials in it so that Prisma can introspect your database schema.
Note: You can also pass the database credentials via a
.env
file. Read more about it here
1Using PostgreSQL:23```prisma4//schema.prisma56datasource db {7 provider = "postgres"8 url = "postgresql://USER:PASSWORD@localhost:5432/DATABASE"9}10```1112Using MySQL:1314```prisma15//schema.prisma1617datasource db {18 provider = "mysql"19 url = "mysql://USER:PASSWORD@localhost:3306/DATABASE"20}21```2223Using SQLite:2425```prisma26//schema.prisma2728datasource db {29 provider = "sqlite"30 url = "file:./dev.db"31}32```
- Introspect your database:
$npx prisma db pull
- Generate the Prisma Client. Add the following block at the top of your
schema.prisma
file:
1generator prisma_client {2 provider = "prisma-client-js"3}
The plugin will take care of generating the Prisma Client for you after that.
You're ready to start working!
Example
Given a Prisma schema (left), you will be able to project these Prisma models onto your API and expose operations against them (middle) resulting in the GraphQL Schema (right).
Note:
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1generator prisma_client {2 provider = "prisma-client-js"3}45model User {6 id String @id @default(cuid())7 email String @unique8 birthDate DateTime9}1011model Post {12 id String @id @default(cuid())13 author User[]14}15
1import { schema } from 'nexus'23schema.queryType({4 definition(t) {5 t.crud.user()6 t.crud.users({7 ordering: true,8 })9 t.crud.post()10 t.crud.posts({11 filtering: true,12 })13 },14})1516schema.mutationType({17 definition(t) {18 t.crud.createOneUser()19 t.crud.createOnePost()20 t.crud.deleteOneUser()21 t.crud.deleteOnePost()22 },23})2425schema.objectType({26 name: 'User',27 definition(t) {28 t.model.id()29 t.model.email()30 t.model.birthDate()31 t.model.posts()32 },33})3435schema.objectType({36 name: 'Post',37 definition(t) {38 t.model.id()39 t.model.author()40 },41})
1scalar DateTime23input DateTimeFilter {4 equals: DateTime5 gt: DateTime6 gte: DateTime7 in: [DateTime!]8 lt: DateTime9 lte: DateTime10 not: DateTime11 notIn: [DateTime!]12}1314type Mutation {15 createOnePost(data: PostCreateInput!): Post!16 createOneUser(data: UserCreateInput!): User!17 deleteOnePost(where: PostWhereUniqueInput!): Post18 deleteOneUser(where: UserWhereUniqueInput!): User19}2021enum OrderByArg {22 asc23 desc24}2526type Post {27 author(after: String, before: String, first: Int, last: Int): [User!]!28 id: ID!29}3031input PostCreateInput {32 author: UserCreateManyWithoutAuthorInput33 id: ID34}3536input PostCreateManyWithoutPostsInput {37 connect: [PostWhereUniqueInput!]38 create: [PostCreateWithoutAuthorInput!]39}4041input PostCreateWithoutAuthorInput {42 id: ID43}4445input PostFilter {46 every: PostWhereInput47 none: PostWhereInput48 some: PostWhereInput49}5051input PostWhereInput {52 AND: [PostWhereInput!]53 author: UserFilter54 id: StringFilter55 NOT: [PostWhereInput!]56 OR: [PostWhereInput!]57}5859input PostWhereUniqueInput {60 id: ID61}6263type Query {64 post(where: PostWhereUniqueInput!): Post65 posts(after: String, before: String, first: Int, last: Int, where: PostWhereInput): [Post!]!66 user(where: UserWhereUniqueInput!): User67 users(after: String, before: String, first: Int, last: Int, orderBy: UserOrderByInput): [User!]!68}6970input StringFilter {71 contains: String72 endsWith: String73 equals: String74 gt: String75 gte: String76 in: [String!]77 lt: String78 lte: String79 not: String80 notIn: [String!]81 startsWith: String82}8384type User {85 birthDate: DateTime!86 email: String!87 id: ID!88 posts(after: String, before: String, first: Int, last: Int): [Post!]!89}9091input UserCreateInput {92 birthDate: DateTime!93 email: String!94 id: ID95 posts: PostCreateManyWithoutPostsInput96}9798input UserCreateManyWithoutAuthorInput {99 connect: [UserWhereUniqueInput!]100 create: [UserCreateWithoutPostsInput!]101}102103input UserCreateWithoutPostsInput {104 birthDate: DateTime!105 email: String!106 id: ID107}108109input UserFilter {110 every: UserWhereInput111 none: UserWhereInput112 some: UserWhereInput113}114115input UserOrderByInput {116 birthDate: OrderByArg117 email: OrderByArg118 id: OrderByArg119}120121input UserWhereInput {122 AND: [UserWhereInput!]123 birthDate: DateTimeFilter124 email: StringFilter125 id: StringFilter126 NOT: [UserWhereInput!]127 OR: [UserWhereInput!]128 posts: PostFilter129}130131input UserWhereUniqueInput {132 email: String133 id: ID134}
Recipes
Projecting Prisma model fields
Exposing one of your Prisma models in your GraphQL API
1schema.objectType({2 name: 'Post',3 definition(t) {4 t.model.id()5 t.model.title()6 t.model.content()7 },8})
Simple computed GraphQL fields
You can add computed fields to a GraphQL object using the standard GraphQL Nexus API.
1schema.objectType({2 name: "Post",3 definition(t) {4 t.model.id()5 t.model.title()6 t.model.content()7 t.string("uppercaseTitle", {8 resolve({ title }, args, ctx) {9 return title.toUpperCase(),10 }11 })12 },13})
Complex computed GraphQL fields
If you need more complicated logic for your computed field (e.g. have access to some information from the database), you can use the prisma
instance that's attached to the context and implement your resolver based on that.
1schema.objectType({2 name: 'Post',3 definition(t) {4 t.model.id()5 t.model.content()6 t.string('anotherComputedField', {7 async resolve(_parent, _args, ctx) {8 const databaseInfo = await ctx.prisma.someModel.someOperation(...)9 const result = doSomething(databaseInfo)10 return result11 }12 })13 }14})
Project a Prisma field to a differently named GraphQL field
1schema.objectType({2 name: 'Post',3 definition(t) {4 t.model.id()5 t.model.content({6 alias: 'body',7 })8 },9})
Publish full-featured reads on a Prisma model
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1schema.queryType({2 definition(t) {3 t.crud.post()4 t.crud.posts({5 ordering: true,6 filtering: true,7 })8 },9})
Publish writes on a Prisma model
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1schema.mutationType({2 definition(t) {3 t.crud.createPost()4 t.crud.updatePost()5 t.crud.updateManyPost()6 t.crud.upsertPost()7 t.crud.deletePost()8 t.crud.deleteManyPost()9 },10})
Publish customized reads on a Prisma model
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1schema.queryType({2 definition(t) {3 t.crud.posts({4 filtering: {5 id: true,6 title: true,7 },8 ordering: { title: true },9 })10 },11})
Publish autogenerated mutations with computed input values
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1schema.mutationType({2 definition(t) {3 /*4 Assuming our prisma model for User has a createdByBrowser field,5 this removes it from the input type but ensures the value is6 inferred from context and passed to Prisma Client.7 */8 t.crud.createOneUser({9 computedInputs: {10 createdByBrowser: ({ args, ctx, info }) => ctx.session.browser,11 },12 })13 },14})
Globally remove a field from input types and infer its value
🚧 Work in progress.
1nexusPrismaPlugin({2 ...other config...3 /*4 Remove fields named "user" from all input types. When resolving5 a request whose data contains any of these types, the value is inferred6 from context and passed to Prisma Client, even if it's nested. This is great for7 creating data associated with one user's account.8 */9 computedInputs: {10 user: ({ args, ctx, info }) => ({11 connect: {12 id: ctx.userId,13 },14 }),15 },16})
1schema.mutationType({2 definition(t) {3 t.crud.createOnePost()4 },5})
Without computedInputs
:
1mutation createOnePost {2 createOnePost(3 data: {4 title: "Automatically generate clean APIs!"5 image: { url: "https://example.com/images/prancing-unicorns", user: { connect: { id: 1 } } }6 user: { connect: { id: 1 } }7 }8 )9}
With computedInputs
:
1mutation createOnePost {2 createOnePost(3 data: {4 title: "Automatically generate clean APIs!"5 image: { url: "https://example.com/images/prancing-unicorns" }6 }7 )8}
Publish model writes along side Prisma Client-resolved fields
t.crud
is an experimental feature. You must explicitly enable it via the plugin options.
1schema.mutationType({2 definition(t) {3 t.crud.createUser()4 t.crud.updateUser()5 t.crud.deleteUser()6 t.crud.deletePost()78 t.field('createDraft', {9 type: 'Post',10 args: {11 title: stringArg(),12 content: nullable(stringArg()),13 },14 resolve: (parent, { title, content }, ctx) => {15 return ctx.prisma.posts.createPost({ title, content })16 },17 })1819 t.field('publish', {20 type: nullable('Post'),21 args: {22 id: idArg(),23 },24 resolve(parent, { id }, ctx) {25 return ctx.prisma.posts.updatePost({26 where: { id },27 data: {28 published: true,29 },30 })31 },32 })33 },34})