-
Notifications
You must be signed in to change notification settings - Fork 3
Usage of Nexus Graphql
In this project, we use nexus for creating our schema with a code-first approach. Code-first approach gives a better developer experience in typescript.
As read in [Project Structure)[https://github.com/Organisasjonskollegiet/voting-backend/wiki/Project-Structure] page, each package is splitted into typedefs, query, mutation and eventual subscriptions.
When defining one of these Root-types we use the corresponding rootField
type, such as queryField
, mutationField
, subscriptionField
.
This project has chosen to use rootTypes
as its standard. The advantage of extendType
is that we can define multiple operations in one definition(t)
. However one such definintion can quickly become very big. Therefor its easier to split each operation into each own variable. An advantage with this approach is that each operation is more readable. With rootFields
each operation has less tabs, which makes it all more readable. It's also hard to mistake which rootType
is in usage.
Rule of thumb: If the input has more than 3 arguments, create an inputObjectType
inside of typedefs.ts
. If the Input has less than 3 arguments you can define the argument types inline
nexus-prisma-plugin
provides with a lot of magic and great integration. The plugin will read the prisma-schema and automatically convert them into fields which you can access with t.model
. These prisma fields will automatically convert to corresponding graphql-types.
However we should try to mostly define the graphql-fields manually. The plugin is quite mature, however it seems like it hasn't been updated in a while. Therefor we should use the plugin cautiously, even if it can save us a ton of type using it everywhere. In my opinion, we can use t.model when defining custom scalar types, such as DateTime
, Json
etc.
// Without plugin
export const User = objectType({
name: 'User',
definition(t) {
t.nonNull.id('id');
t.nonNull.string('username');
t.nonNull.string('email');
},
});
// With plugin
export const User = objectType({
name: 'User',
definition(t) {
t.model.();
t.model.username();
t.model.email();
},
});
In addition, we can also use it for simple relations such as One-To-One.
// Without plugin
import { Participant as ParticipantModel } from '@prisma/client';
// Suffix the Prisma model type with `Model` so it doesnt clash with variables
export const Participant = objectType({
name: 'Participant',
definition(t) {
t.nonNull.field('role', { type: Role });
t.nonNull.boolean('isVotingEligible');
t.field('user', {
type: User,
resolve: async (source, _, ctx) => {
const { userId } = source as ParticipantModel; //
const user = await ctx.prisma.user.findUnique({ where: { id: userId }, rejectOnNotFound: true });
return user;
},
});
},
});
// With plugin
export const Participant = objectType({
name: 'Participant',
definition(t) {
t.nonNull.field('role', { type: Role });
t.nonNull.boolean('isVotingEligible');
t.model.user();
},
});