Nexus: Split queries and mutations to multiple files

Created on 3 Jan 2019  路  6Comments  路  Source: graphql-nexus/nexus

Hey,
I really like nexus, but I would like to see a better solution how to split queries and mutations to multiple files. Because with more complex applications its hard to follow one big file with everything inside. So what is the best solution for it right now? Are there any plans on how to address this kind of issue?

Most helpful comment

export const posts = queryField("posts", {
  type: "Post",
  list: true,  // <--- this
  resolve: async (parent, args, ctx: Context) => {
    try {
      const userId = getUserId(ctx);
      const posts = await ctx.prisma
        .user({ id: userId })
        .posts()
      console.log("POSTS: ", posts);
      return posts;
    } catch (err) {
      console.error("ERROR posts query: ", err);
      throw err;
    }
  }
});

All 6 comments

Hey @Huvik!

Because with more complex applications its hard to follow one big file with everything inside.

I assume you mean splitting individual fields for a type, since you can already split types across multiple files.

My thought on an API here was was we could add an extendType which would require a type by that name is defined and imported into the schema, other than the Query / Mutation type since those are implicitly assumed to exist:

export const UserMutations = extendType('Mutation', (t) => {
   t.field('addUser', 'User', {
     args: {...}
   });
   t.field('updateUser', 'User', {
     args: {...}
   });
})

Does this make sense to you as an API? I'll add this to the todo list

@tgriesser I really like extendType idea, because it could be translated to more use cases. This way it's more flexible and cleaner than having everything in one file.

@tgriesser Do you have any rough idea when it could be introduced?

Hey @Huvik!

You can split your code something like that:

1) intex.ts - nothing changes here

import { GraphQLServer } from 'graphql-yoga'
import { prisma } from './generated/prisma-client'
import * as path from 'path'
import { makePrismaSchema } from 'nexus-prisma'
import { permissions } from './permissions'
import * as allTypes from './resolvers'
import datamodelInfo from './generated/nexus-prisma'

...

const server = new GraphQLServer({
  schema,
  middlewares: [permissions],
  context: request => {
    return {
      ...request,
      prisma,
    }
  },
})

2) ./resolvers/index.ts

import { Query } from './Query'
import { Mutation } from './Mutation'
import { User } from './User'
import { Post } from './Tenant'
import { AuthPayload } from './AuthPayload'

export const resolvers = [
  Query,
  Mutation,
  User,
  Post,
  AuthPayload
]

3) ./resolvers/Mutations/index.ts

import { prismaObjectType, makePrismaSchema } from 'nexus-prisma'

import { signup } from './signup'
import { login } from './login'
import { sendLinkValidateEmail } from './sendLinkValidateEmail'
import { validateEmail } from './validateEmail'
import { forgetPassword } from './forgetPassword'
import { resetPassword } from './resetPassword'
import { updatePassword } from './updatePassword'

export const DefaultMutations = prismaObjectType({
  name: 'Mutation',
  definition(t) {
    t.prismaFields([
        'createFile',
        'deleteFile',
        'updateFile',
        'createBuilding'
    ])
  }
})

export const Mutation = {
    DefaultMutations,
    signup,
    login,
    sendLinkValidateEmail,
    validateEmail,
    forgetPassword,
    resetPassword,
    updatePassword
}

4) ./resolvers/Mutations/signup.ts

import { stringArg, idArg, mutationField } from 'nexus'
import * as crypto from "crypto";
import { APP_SECRET, getUserId } from '../../utils'
import { hash, compare } from 'bcrypt'
import { sign } from 'jsonwebtoken'

export const signup = mutationField("signup", {
    type: 'AuthPayload',
    args: {
        name: stringArg({ nullable: true }),
        email: stringArg(),
        password: stringArg(),
    },
    async resolve(parent, { name, email, password}, ctx) {
        const hashedPassword = await hash(password, 10)
        const resetPasswordToken = crypto.randomBytes(64).toString("hex");
        const validateEmailToken = crypto.randomBytes(64).toString("hex");

        const user = await ctx.prisma.createUser({
          name,
          email,
          password: hashedPassword,
          resetPasswordToken,
          validateEmailToken,
        })

        return {
          token: sign({ userId: user.id }, APP_SECRET),
          user,
        }
      },
  });

@bizmedia your answer is awesome

Could you please tell me how to return an array when doing it as you demonstrated?

My current issue is that I'm trying to return a list of posts like this:

export const posts = queryField("posts", {
  type: "Post",
  resolve: async (parent, args, ctx: Context) => {
    try {
      const userId = getUserId(ctx);
      const posts = await ctx.prisma
        .user({ id: userId })
        .posts()
      console.log("POSTS: ", posts);
      return posts;
    } catch (err) {
      console.error("ERROR posts query: ", err);
      throw err;
    }
  }
});

But when I go to the playground it is stating that it will only return the object of Post not like [Post]!

export const posts = queryField("posts", {
  type: "Post",
  list: true,  // <--- this
  resolve: async (parent, args, ctx: Context) => {
    try {
      const userId = getUserId(ctx);
      const posts = await ctx.prisma
        .user({ id: userId })
        .posts()
      console.log("POSTS: ", posts);
      return posts;
    } catch (err) {
      console.error("ERROR posts query: ", err);
      throw err;
    }
  }
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

deadcoder0904 picture deadcoder0904  路  6Comments

chrisdrackett picture chrisdrackett  路  3Comments

antonbramsen picture antonbramsen  路  3Comments

tl-jarvis-prestidge picture tl-jarvis-prestidge  路  7Comments

saostad picture saostad  路  3Comments