Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
nexus-prisma
Advanced tools
[![trunk](https://github.com/prisma/nexus-prisma/actions/workflows/trunk.yml/badge.svg)](https://github.com/prisma/nexus-prisma/actions/workflows/trunk.yml)
⚠️ Currently in early preview - not to be used in Production unless you're willing to live on the bleeding edge and give us feedback, which we would welcome!. Follow progress here.
Official Prisma plugin for Nexus.
Install dependencies
npm add nexus-prisma nexus graphql @prisma/client
npm add --dev prisma
nexus
graphql
and@prisma/client
are peer dependencies.prisma
is for the Prisma CLI which you'll probably want during development.
If you use
nexus@=<1.0
then you must uset.field(<NAME>, <CONFIG>)
instead oft.field(<CONFIG>)
. The Nexus Prisma docs assume the latter form.
Add a nexus-prisma
generator block to your Prisma Schema.
Run prisma generate
in your terminal.
Import models from nexus-prisma
and then pass them to your Nexus type definition and field definition configurations. In this way you will be effectively projecting models from your data layer into GraphQL types in your API layer.
generator client {
provider = "prisma-client-js"
}
generator nexusPrisma {
provider = "nexus-prisma"
}
/// This is a user!
model User {
/// This is an id!
id String @id
}
prisma generate
import { User } from 'nexus-prisma'
import { makeSchema, objectType } from 'nexus'
export const schema = makeSchema({
types: [
objectType({
name: User.$name
description: User.$description
definition(t) {
t.field(User.id)
// t.field(User.id.name, User.id) <-- For nexus@=<1.0 users
}
})
]
})
DateTime
& Json
Bytes
BigInt
Decimal
t.model
? t.crud
?$ prisma generate
.nexus-prisma
which hits the generated entrypoint.Note: ⛑ The following use abbreviated examples that skip a complete setup of passing Nexus type definition to Nexus'
makeSchema
. If you are new to Nexus, consider reading the official Nexus tutorial before jumping into Nexus Prisma.
Following the same philosophy as Prisma Client, Nexus Prisma uses generation to create an API that feels tailor made for your project.
model User {
id String @id
}
import { User } from 'nexus-prisma'
import { objectType } from 'nexus'
objectType({
name: User.$name
description: User.$description
definition(t) {
t.field({
type: User.id.type,
description: User.id.description
})
}
})
Every enum defined in your Prisma schema becomes importable as a Nexus enum type definition configuration. This makes it trivial to project enums from your database layer into your API layer.
enum SomeEnum {
foo
bar
}
import { SomeEnum } from 'nexus-prisma'
import { enumType } from 'nexus'
SomeEnum.name // 'SomeEnum'
SomeEnum.members // ['foo', 'bar']
enumType(SomeEnum)
Like GraphQL, Prisma has the concept of scalar types. Some of the Prisma scalars can be naturally mapped to standard GraphQL scalars. The mapping is as follows:
Prisma Standard Scalar to GraphQL Standard Scalar Mapping
Prisma | GraphQL |
---|---|
Boolean | Boolean |
String | String |
Int | Int |
Float | Float |
String with @id | ID |
Int with @id | ID | Int (configurable) |
However some of the Prisma scalars do not have a natural standard representation in GraphQL. For these cases Nexus Prisma generates code that references type names matching those scalar names in Prisma. Then, you are expected to define those custom scalar types in your GraphQL API. Nexus Prisma ships with pre-defined mappings in nexus-prisma/scalars
you can use for convenience. The mapping is as follows:
Prisma Standard-Scalar to GraphQL Custom-Scalar Mapping
Prisma | GraphQL | Nexus t Helper | GraphQL Scalar Implementation | Additional Info |
---|---|---|---|---|
Json | Json | json | JsonObject | |
DateTime | DateTime | dateTime | DateTime | |
BigInt | BigInt | bigInt | BigInt | JavaScript BigInt |
Bytes | Bytes | bytes | Byte | Node.js Buffer |
Decimal | Decimal | decimal | (internal) | Uses Decimal.js |
Note: Not all Prisma scalar mappings are implemented yet:
Unsupported
Note: BigInt is supported in Node.js since version 10.4.0 however to support BigInt in
JSON.parse
/JSON.stringify
you must usejson-bigint-patch
otherwise BigInt values will be serialized as strings.
You can use your own GraphQL Scalar Implementation, however, you must adhear to the above Prisma/GraphQL name mapping defined above.
Here is an example using Nexus Prisma's pre-defined GraphQL custom scalars:
import NexusPrismaScalars from 'nexus-prisma/scalars'
import { makeSchema } from 'nexus'
makeSchema({
types: [NexusPrismaScalars],
})
There is a recipe below showing how to add your own custom scalars if you want.
You can project relations into your API with Nexus Prisma. Nexus Prisma even includes the resolver you'll need at runtime to fulfill the projection by automating use of your Prisma Client instance.
Please note that not all kinds of relationships are supported yet. Details about projecting each kind of relation are documented in their respective sections. This section only contains general documentation common to all.
To project relations you must by default expose an instance of Prisma Client on the GraphQL context under the key name prisma
. You can customize which context property Nexus Prisma should look for your Prisma Client.
import { ApolloServer } from 'apollo-server'
import { PrismaClient } from '@prisma/client'
import schema from './your/schema/somewhere'
const prisma = new PrismaClient()
new ApolloServer({
schema,
context() {
return {
prisma,
}
},
})
You can project 1:1 relationships into your API.
The integration test suite is a useful reference as it is declarative (easy to read) and gives a known-working example spanning from database all the way to executed GraphQL document.
// Database Schema
model User {
id String @id
profile Profile @relation(fields: [profileId], references: [id])
profileId String
}
model Profile {
id String @id
user User?
}
// API Schema
import { User, Profile } from 'nexus-prisma'
queryType({
definition(t) {
t.nonNull.list.nonNull.field('users', {
type: 'User',
resolve(_, __, ctx) {
return ctx.prisma.user.findMany()
},
})
},
})
objectType({
name: User.$name,
definition(t) {
t.field(User.id)
t.field(User.profile)
},
})
objectType({
name: Profile.$name,
definition(t) {
t.field(Profile.id)
},
})
# API Schema Represented in GraphQL SDL (this is generated by Nexus)
type Query {
users: [User!]!
}
type User {
id: ID
profile: Profile
}
type Profile {
id: ID
}
// Example Database Data (for following example)
await prisma.user.create({
data: {
id: 'user1',
profile: {
create: {
id: 'profile1',
},
},
},
})
# Example API Client Query
query {
users {
id
profile {
id
}
}
}
{
"data": {
"users": [
{
"id": "user1",
"profile": {
"id": "profile1"
}
}
]
}
}
Prisma requires that a 1:1 relationship has one side that is optional. For example in the following it is not possible for Profile
to have a required relationship to User
. For more detail you can read the Prisma docs about this here.
model User {
id String @id
profile Profile @relation(fields: [profileId], references: [id])
profileId String
}
model Profile {
id String @id
user User? // <-- "?" required
}
Prisma inherits this limitation from databases. In turn Nexus Prisma inherits this limitation from Prisma. For example consider this projection and then look at the resulting GraphQL SDL representation.
import { User, Profile } from 'nexus-prisma'
objectType({
name: User.$name,
definition(t) {
t.field(User.id)
t.field(User.profile)
},
})
objectType({
name: Profile.$name,
definition(t) {
t.field(Profile.id)
t.field(User.profile)
},
})
type User {
id: ID
profile: Profile!
}
type Profile {
id: ID
user: User # <-- Nullable!
}
This limitation may be a problem for your API. There is an issue track this that you can subscribe to if interested. As a workaround for now you can do this:
objectType({
name: Profile.$name,
definition(t) {
t.field(Profile.id)
t.field({
...User.profile,
type: nonNull(User.profile.type),
})
},
})
You can project 1:n relationships into your API.
The integration test suite is a useful reference as it is declarative (easy to read) and gives a known-working example spanning from database all the way to executed GraphQL document.
// Database Schema
model User {
id String @id
posts Post[]
}
model Post {
id String @id
author User? @relation(fields: [authorId], references: [id])
authorId String
}
// API Schema
import { User, Post } from 'nexus-prisma'
queryType({
definition(t) {
t.nonNull.list.nonNull.field('users', {
type: 'User',
resolve(_, __, ctx) {
return ctx.prisma.user.findMany()
},
})
},
})
objectType({
name: User.$name,
definition(t) {
t.field(User.id)
t.field(User.posts)
},
})
objectType({
name: Post.$name,
definition(t) {
t.field(Post.id)
},
})
# API Schema Represented in GraphQL SDL (this is generated by Nexus)
type Query {
users: [User]
}
type User {
id: ID!
posts: [Post!]!
}
type Post {
id: ID!
}
// Example Database Data (for following example)
await prisma.user.create({
data: {
id: 'user1',
posts: {
create: [{ id: 'post1' }, { id: 'post2' }],
},
},
})
# Example API Client Query
query {
users {
id
posts {
id
}
}
}
{
"data": {
"users": [
{
"id": "user1",
"posts": [
{
"id": "post1"
},
{
"id": "post2"
}
]
}
]
}
}
prismaClientContextField: string
@summary The name of the GraphQL context field to get an instance of Prisma Client from.
@remarks The instance of Prisma Client found here is accessed in the default resolvers for relational fields.
@default "prisma"
@example
// src/main.ts
import { PrismaClient } from '@prisma/client'
import { ApolloServer } from 'apollo-server'
import { makeSchema } from 'nexus'
import { User, Post, $settings } from 'nexus-prisma'
new ApolloServer({
schema: makeSchema({
types: [],
}),
context() {
return {
db: new PrismaClient(), // <-- You put Prisma client on the "db" context property
}
},
})
$settings({
prismaClientContextField: 'db', // <-- Tell Nexus Prisma
})
prismaClientImportId: string
@summary Where Nexus Prisma will try to import your generated Prisma Client from. You should not need to configure this normally because Nexus Prisma generator automatically reads the Prisma Client generator output
setting if you have set it. The value here will be used in a dynamic import thus following Node's path resolution rules. You can pass a node_modules package like foo
@prisma/client
, @my/custom/thing
etc. or you can pass an absolute module/file path /my/custom/thing
/ /my/custom/thing/index.js
or finally a relative path to be resolved relative to the location of Nexus Prisma source files (you probably don't want this).
@default @prisma/client
@remarks Nexus Prisma imports Prisma client internally for two reasons: 1) validation wherein a class reference to Prisma Client is needed for some instanceof
checks and 2) for acquiring the DMMF as Nexus Prisma relies on some post-processing done by Prisma Client generator.
@example
// src/main.ts
import { PrismaClient } from '@prisma/client'
import { ApolloServer } from 'apollo-server'
import { makeSchema } from 'nexus'
import { User, Post, $settings } from 'nexus-prisma'
new ApolloServer({
schema: makeSchema({
types: [],
}),
})
$settings({
prismaClientImportId: '@my/custom/thing',
})
You are able to control certain aspects of the Nexus Prisma code generation.
Create a configuration file named any of:
nexusPrisma.ts / nexus-prisma.ts / nexus_prisma.ts
In one of the following directories:
Project Root – The directory containing your project's package.json. Example:
├── nexus-prisma.ts
└── package.json
Primsa Directory – The directory containing your Prisma schema. Example:
├── prisma/nexus-prisma.ts
└── package.json
If you have not already, install ts-node
which nexus-prisma
will use to read your configuration module.
Import the settings singleton and make your desired changes. Example:
import { settings } from 'nexus-prisma/generator'
settings({
projectIdIntToGraphQL: 'ID',
})
projectIdIntToGraphQL: 'ID' | 'Int'
@summary
Map Prisma model fields of type Int
with attribute @id
to ID
or Int
.@default
Int
docPropagation.JSDoc: boolean
@summary
Should Prisma Schema docs propagate as JSDoc?@default
true
docPropagation.GraphQLDocs: boolean
@summary
Should Prisma Schema docs propagate as GraphQL docs?@remarks
When this is disabled it will force .description
property to be undefined
. This is for convenience, allowing you to avoid post-generation data manipulation or consumption contortions.@default
true
All String
fields with @id
attribute in your Prisma Schema get projected as GraphQL ID
types rather than String
types.
model User {
id String @id
}
import { User } from 'nexus-prisma'
import { objectType } from 'nexus'
objectType({
name: User.$name
description: User.$description
definition(t) {
t.field(User.id)
}
})
type User {
id: ID
}
/// A user.
model User {
/// A stable identifier to find users by.
id String @id
}
import { User } from 'nexus-prisma'
import { objectType } from 'nexus'
User.$description // JSDoc: A user.
User.id.description // JSDoc: A stable identifier to find users by.
objectType({
name: User.$name
description: User.$description
definition(t) {
t.field(User.id)
}
})
"""
A user.
"""
type User {
"""
A stable identifier to find users by.
"""
id: ID
}
Can be disabled in gentime settings.
/// A user.
model User {
/// A stable identifier to find users by.
id String @id
}
import { User } from 'nexus-prisma'
User // JSDoc: A user.
User.id // JSDoc: A stable identifier to find users by.
Nexus Prisma supports both ESM and CJS. There shouldn't be anything you need to "do", things should "just work". Here's the highlights of how it works though:
These are finer points that aren't perhaps worth a top-level point but none the less add up toward a thoughtful developer experience.
When your project is in a state where the generated Nexus Prisma part is missing (new repo clone, reinstalled deps, etc.) Nexus Prisma gives you a default runtime export named PleaseRunPrismaGenerate
and will error with a clear message.
When nexus-prisma
is imported it will validate that your project has peer dependencies setup correctly.
If a peer dependency is not installed it nexus-prisma
will log an error and then exit 1. If its version does not satify the range supported by the current version of nexus-prisma
that you have installed, then a warning will be logged. If you want to opt-out of this validation (e.g. you're using a bundler) then set an envar as follows:
NO_PEER_DEPENDENCY_CHECK=true|1
PEER_DEPENDENCY_CHECK=false|0
nexus-prisma/scalars
offers a default export you can easily auto-import by name: NexusPrismaScalars
.Nexus Prisma generates default GraphQL resolvers for your model relation fields. However you may want to run custom logic in the resolver. This is easy to do. The following show a few ways.
Wrap Style You can access the default resolver within your own custom resolver.
objectType({
name: User.$name,
definition(t) {
t.field(User.id)
t.field({
...User.posts,
async resolve(...args) {
// Your custom before-logic here
const result = await User.posts.resolve(...args)
// Your custom after-logic here
return result
},
})
},
})
Replace Style You can simply opt out of using the default resolver completely:
objectType({
name: User.$name,
definition(t) {
t.field(User.id)
t.field({
...User.posts,
async resolve(...args) {
// Your custom logic here
},
})
},
})
The following is a brief example how you could add your own custom GraphQL custom scalars to satisfy Nexus Prisma. Note that most of the time using the defaults exported by nexus-prisma/scalars
will probably be good enough for you.
import { GraphQLScalarType } from 'graphql'
import { JSONObjectResolver, DateTimeResolver } from 'graphql-scalars'
import { asNexusMethod, makeSchema } from 'nexus'
const jsonScalar = new GraphQLScalarType({
...JSONObjectResolver,
// Override the default 'JsonObject' name with one that matches what Nexus Prisma expects.
name: 'Json',
})
const dateTimeScalar = new GraphQLScalarType(DateTimeResolver)
makeSchema({
types: [asNexusMethod(jsonScalar, 'json'), asNexusMethod(dateTimeScalar, 'dateTime')],
})
When working with bundlers, it probably makes sense to disable the rutnime peer dependency check system since the bundle step is merging the dependency tree into a single file and may be moved to run standalone away from the original project manifest (e.g. in a docker container).
Instructions to do this can be found here.
nexus-prisma
has tests showing that it supports ncc
. Other bundlers are not tested and may or may not work. It is our goal however that nexus-prisma not be the reason for any popular bundler to not work on your project. So if you encounter a problem with one (e.g. parcel
), open an issue here and we'll fix the issue including an addition to our test suite.
nexus-prisma@=<0.20
Versions of nexus-prisma
package prior to 0.20
were a completely different version of the API, and had also become deprecated at one point to migrate to nexus-plugin-prisma
when Nexus Framework was being worked on. All of that is history.
nexus@=<1.0
The release of Nexus 1.1 introduced an overload to t.field
allowing improved usage of Nexus Prisma. The difference is as follows. Note if you prefer the older way that is and always will be supported too.
import { User } from 'nexus-prisma'
import { makeSchema, objectType } from 'nexus'
export const schema = makeSchema({
types: [
objectType({
name: User.$name
description: User.$description
definition(t) {
+ t.field(User.id) // <-- for nexus@>=1.1 users
- t.field(User.id.name, User.id) // <-- For nexus@=<1.0 users
}
})
]
})
We only officially support what we test.
We test Node versions that are Active LTS
and Current
. For which versions of Node that equals you can refer to our tests or look here: https://nodejs.org/en/about/releases.
@prisma/client
We only officially support what we test.
We test Prisma Client versions 2.30.x
, 2.29.x
.
ts-node
We only officially support what we test.
We test ts-node
versions 10.x
.
Reminder: ts-node
is an optional peer dep required when you are working with the generator settings.
We test the latest versions of @prisma/client
against Node 16 and 14 on Ubuntu, macOS, and Windows while past versions of @prisma/client
are tested only against Node 16 on Ubuntu. We do this to keep the CI test matris reasonable as the number of past @prisma/client
versions supported could grow long.
We only support the latest patch version of a minor series. For example imagine that there was a bug when nexus-prisma
was integrated with @prisma/client@2.30.1
but not when integrated with @prisma/client@2.30.2
. Our policy would be that users should upgrade to the latest 2.30.x
version, and that we would not release any no code changes of nexus-prisma
.
FAQs
nexus-prisma
The npm package nexus-prisma receives a total of 6,151 weekly downloads. As such, nexus-prisma popularity was classified as popular.
We found that nexus-prisma demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.