jasci
06/21/2021, 8:11 AMgraphql-code-generator
.
1. How to properly ‘type’ the resolvers ?
I typed the resolvers itself with types generated from the graphql-code-generator
for example:
const updateUser: MutationResolvers['updateUser'] = <resolver code>
But the problem is - return type from the resolver ( prisma.user.update
call ) is User (prisma) and it does not include the relations, and here is the conflict ( ’Type ‘User’ is missing the following properties from type ‘User’: adminOf, employeeOf, accounts’ or similar ones ). Basically for every model/type I’ve got 2 type definitions and in many cases they differ.
Here is the User type in the app schema:
type User {
email: String!
firstName: String!
lastName: String!
phone: String
billingAddress: Address
shippingAddress: Address
adminOf: [Company!]!
employeeOf: [Company!]!
accounts: [Account!]!
adminOfVendors: [Vendor]
}
Here is typings for the User model (prisma):
export type User = {
id: string
emailVerificationToken: string | null
passwordResetToken: string | null
superUser: boolean
email: string
firstName: string
lastName: string
password: string
phone: string | null
billingAddress: Prisma.JsonValue | null
shippingAddress: Prisma.JsonValue | null
}
Here is typings for the User type (graphql-code-generator):
export type User = {
__typename?: 'User';
email: Scalars['String'];
firstName: Scalars['String'];
lastName: Scalars['String'];
phone?: Maybe<Scalars['String']>;
billingAddress?: Maybe<Address>;
shippingAddress?: Maybe<Address>;
adminOf: Array<Company>;
employeeOf: Array<Company>;
accounts: Array<Account>;
adminOfVendors?: Maybe<Array<Maybe<Vendor>>>;
};
Maybe there is some universal practice of typing the API with 2 main type files (for the prisma datamodel and app schema) ? I’m new to the typescript.
2. If my app schema defines some fields which are relations (User example):
adminOf: [Company!]!
employeeOf: [Company!]!
accounts: [Account!]!
adminOfVendors: [Vendor]
I do need to use include
in the Prisma Client in every resolver that should return User type? Because they are not returned by default.
3. T*ype resolvers:*
For example I’ve got Company
type and it has field admin
which is of type User.
When I write type resolvers for the Company
type, specifically for the admin
field, do I also need to use include
in it (to get relations of the User) ?
Example:
const resolvers = {
Query: {
// ...
},
Mutation: {
// ...
},
Company: {
admin: (parent, args, context) => {
return context.prisma.company.findUnique({
where: { id: parent.id }
}).user()
// Or something like that
return context.prisma.user.findUnique({
where: { id: parent.userId },
include: {
some_relation_field: true
}
})
}
},
}
Sorry for a lot questions, thank you.Eddy Nguyen
06/21/2021, 12:52 PMapollo-server
with graphql-code-generator
. The basic concepts are the same in most GraphQL servers. Let me try to answer your questions one by one:
1. How to match Prisma and GraphQL types: use typescript-resolvers
‘s “mappers”. Documentation. Example config and example mapper file . If you use Prisma’s type as the mapper, you can return Prisma objects directly into resolvers. You will have to write field resolvers to make sure fields are converted to the correct value and types. For example, your Prisma billingAddress
is Prisma.JsonValue | null
. So you will have to have User.billingAdress
resolver to convert it to Maybe<Address>
User: {
...
billingAddress: ({ billingAddress }) => {
// Business logic to convert `Prisma.JsonValue | null` to `Maybe<Address>`
return convertToGraphBillingAddress(billingAddress);
}
}
2. For fields that are relationships, the best way to handle them is to create resolvers for the User
type. This way, you will not overfetch the User
object and only will load relationships if requested by the client. e.g.
User: {
...
adminOf: ({ id }, args, { prisma } ) => {
// Use prisma to find the relationship here. Something like this? I can't remember the syntax
return prisma.user.findUnique({ where: { id } }).includes(...)
}
}
3. If you set up mappers correctly in 1. you can use findUnique
to return User
Prisma object
Company: {
...
admin: (parent, args, context) => {
return context.prisma.company.findUnique({
where: { id: parent.id }
}).user()
})
}
},
jasci
06/21/2021, 2:19 PMUser
means in this resolver?
And when I add type for updateUser
resolver from graphql-code-generator
types, it now expects to return User
(Prisma User, not the one from the app schema), right ?
2. I need to create mappings for all my models which have conflicts, right ?jasci
06/21/2021, 2:23 PMEddy Nguyen
06/21/2021, 11:22 PMUser
will need to return Prisma User
type
2. Yes, every model should be mapped in my opinion for ease of use and consistency. I think you can map directly using the Prisma generated types ( @prisma/client
) instead of going through the mapper file. However, I haven’t tried this so it might or might not workjasci
06/22/2021, 2:06 PMEddy Nguyen
06/22/2021, 2:23 PM