DEV Community

Cover image for Complete Introduction to Fullstack, Type-Safe GraphQL (feat. Next.js, Nexus, Prisma)

Complete Introduction to Fullstack, Type-Safe GraphQL (feat. Next.js, Nexus, Prisma)

Xiaoru Li on June 09, 2020

Complete Introduction to Fullstack, Type-Safe GraphQL (feat. Next.js, Nexus, Prisma) In this post, you'll learn how to build––from scrat...
Collapse
 
sleventyeight profile image
J. C.

This is a great tutorial!

Any chance you could do another post using this same setup but also including RBAC authentication (maybe with next-auth.js.org/) or some other httpOnly cookie solution?

Collapse
 
hexrcs profile image
Xiaoru Li

Sounds like a good idea for a followup post! I'll probably use the nextjs-auth0 package instead of next-auth, or a roll-your-own solution.

Collapse
 
daniz profile image
Daniel Zaremba

I'm definitely voting for a roll-your-own tutorial!
Thanks for the great post!

Collapse
 
dance2die profile image
Sung M. Kim

Awesome tutorial, Xiaoru. Thank you.

Collapse
 
hexrcs profile image
Xiaoru Li

Glad you liked it! πŸ™Œ

Collapse
 
nathanking profile image
Nathan King • Edited

OMG, I'm sorry to bother again but I when I define the graphql schema, I have these extra scalars and t.crud.user()/users() is not generating the Query properly, is not generating the input at all and two scalars are showing up. I defined a dateTime scalar in a previous project. Is this a caching problem?

Collapse
 
hexrcs profile image
Xiaoru Li

Could you provide more details of the error message? Also could you check the versions of your Nexus and Nexus Prisma plugin? There was an update for Nexus after the initial version of this post, and the CRUD helpers now are disabled by default.

I updated this tut and the example repo, please check out this PR and let me know if it solves the problems!

BTW there's no global caching as far as I know, so there shouldn't be a problem if you defined some types in another project.

Collapse
 
nathanking profile image
Nathan King

I tried to run "npx nexus dev" at the start of the tutorial, I have recreated the project twice but I keep on getting this error:


4596 βœ• nexus:glocal The global Nexus CLI you invoked could not hand off to your project-local one becuase it wasn't on disk.

This can happen for example after you have cloned a fresh copy of your project from a remote repository.

Please install your dependencies and try your command again.

Location of the Nexus CLI you invoked: C:\Users\natha\Documents\Web Development\NEXT\nexus-prisma\node_modules\nexus\dist\cli\main.js

Location of your project-local Nexus CLI: C:\Users\natha\Documents\Web Development\NEXT\nexus-prisma\node_modules.bin\main.js

Collapse
 
godie99 profile image
Juan Diego

Try installing the versiΓ³n 0.26.0-next.5 of nexus

Collapse
 
hexrcs profile image
Xiaoru Li

Looks like this can happen on Windows. Are you using the native Windows cmd.exe or WSL?

Collapse
 
nathanking profile image
Nathan King • Edited

Windows cmd... I should probably migrate over to WSL

Thread Thread
 
hexrcs profile image
Xiaoru Li • Edited

Windows support is coming soon to Nexus! However, I'd still recommend you migrate over to WSL or use a Linux dev container of some kind, because most web dev tools and frameworks are created Unix-first.

Thread Thread
 
nathanking profile image
Nathan King

I'm in the process of downloading WSL 2 now 😊 I was going to make the switch anyway but just put it off. I'll try your tute again once it's set up πŸ‘

Thread Thread
 
nathanking profile image
Nathan King • Edited

Just to follow up, I decided to move to Linux and everything worked well!

Thanks so much for the amazing tutorial, it's awesome now that I've made it :P

(Maybe add a disclaimer for Windows users that they might have trouble, if you want)

Thread Thread
 
hexrcs profile image
Xiaoru Li

Nice, great to hear that! :D

Collapse
 
melanke profile image
Gil LB • Edited

Man this Tutorial is great, very well explained with advanced features that a newbie like me could understand, great Job!
I just want to let you know that I was very confused about the fact that I changed my schema.prisma and the Nexus didn't process the change, I had a big trouble until I understand I had to call npx prisma generate to reload the content, so you might want to add this little note on the tutorial, idk.

Also, I have a question: The useAllUsersQuery is being processed via SSR by Next.js right? That is awesome because I don't need to type getServerSideProps. But who does this magic? And can I change this behaviour to work like getStaticProps?

Thank you for this amazing work you did, this is going to be the basis for a lot of projects in my company <3

Collapse
 
jbuck94 profile image
Jamie Buck

Curious about this as well - this code reads like all the GQL queries are happening client-side. Is that correct?

Collapse
 
melanke profile image
Gil LB

Hello @hexrcs can you help us on this? Pleeease πŸ˜… Thanks

Collapse
 
jmales profile image
Jmales

Thanks for the tutorial, lot's of great info!

I'm confused about something though. You said that using graphql-code-generator our source of truth is schema.prisma.

Maybe I'm doing something wrong but I still need to define my objectTypes, queryTypes, mutationTypes and then have my basic queries somewhere right?

import { schema } from 'nexus';

schema.objectType({
  name: 'User',
  definition(t) {
    t.model.userId();
    t.model.name();
  },
});

schema.extendType({
  type: 'Query',
  definition(t) {
    t.crud.user();
    t.crud.users({ filtering: true, ordering: true });
  },
});

schema.extendType({
  type: 'Mutation',
  definition(t) {
    t.crud.createOneUser();
  },
});
Enter fullscreen mode Exit fullscreen mode

And the queries:

export const UsersQuery = /* GraphQL */ `
  query UsersQuery {
    users {
      userId
      name
    }
  }
`;
Enter fullscreen mode Exit fullscreen mode

I feel that I'm writing a lot of redundant code

Collapse
 
hexrcs profile image
Xiaoru Li

Hi there! The source of truth of GraphQL is not schema.prisma, but the GraphQL endpoint powered by Nexus.

You still need to clearly define how the GraphQL schema looks like (eg. object types), because of security (you don't want to expose everything from your DB, think ID and password) and flexibility (you can write your own resolver instead of being restricted to basic CRUD operations on the database).

However, the Nexus-Prisma plugin provides some simple .crud helpers as you can see from the examples, if you just want to directly expose CRUD operations to your GraphQL API. πŸ˜„

Collapse
 
soosap profile image
@soosap

Hey mate, great tutorial. There is one shortcoming in this setup. You are no longer able to spread your nexus schema definition into multiple files. One of the big advantages of the nexus framework is that you no longer need to pull all the dependencies into the schema file manually. This continues to work on localhost:4000/graphql but it no longer works for localhost:3000/api/graphql. The latter endpoint only continues to work when all the objectType, queryType, mutationType, etc. are defined in graphql/schema.ts.

You can try by adapting your repo. Just try to put the objectType for user in a different file. It will break the localhost:3000/api/graphql while localhost:4000/graphql remains in tact. Do you know a workaround for this!

Collapse
 
hexrcs profile image
Xiaoru Li • Edited

Hi there, thanks for the comment! I'm actually not able to reproduce this - perhaps you forgot to import the files where other parts of the schema are defined?

What I did:

  1. Extracted the code for objectType User to another file located at graphql/newFile.ts - next to the original schema.ts
  2. Wrote import "./newFile.ts" at the beginning of graphql/schema.ts

Note that schema from Nexus (is a singleton I believe) is also imported in newFile.ts, and nothing is exported in that file. Here's what I have:

import { schema } from "nexus";

schema.objectType({
  name: "User",
  definition(t) {
    t.model.id();
    t.model.name();
  },
});

In JS/TS, if you import a file, it is scanned through and run by the interpreter, so schema.objectType() is actually executed when the interpreter is done with the line import "./newFile.ts", so it's not static.

Collapse
 
soosap profile image
@soosap • Edited

Yes, that's exactly what I am talking about,

you now have to write import statements for all schema related files in graphql/schema.ts.

If you do that then both GraphQL endpoints (localhost:4000/graphql + localhost:3000/api/graphql) work. However, when you omit the manual import statements in graphql/schema.ts it still continues to work at localhost:4000/graphql, however it no longer works for localhost:3000/api/graphql. For me not dealing with imports in graphql/schema.ts seemed like a nice behaviour of the nexus framework. I was trying to understand if I could avoid the import statements somehow in nextjs localhost:3000/api/graphql?

Thread Thread
 
hexrcs profile image
Xiaoru Li • Edited

I'm not sure why it would continue to work with Nexus dev server's /graphql route, but my guess is that it's due to some caching not being invalidated by Nexus (probably a bug, I'll try to dig into it). The correct behavior should be it fails as well. :)

Edit: Normally, Nexus actually scans the entire project for import {schema} from 'nexus', if an entry point is not specified.

I think the problem you are encountering is because somehow Nexus imported the external schema after the Nexus app has assembled. Actually, when working with Next.js, it's not recommended to have multiple files that import the same part (like use, schema) from Nexus.

Collapse
 
armaandh profile image
Armaan Dhanji

Awesome tutorial! Are you going to be finishing up your egghead video series on Prisma?

Collapse
 
hexrcs profile image
Xiaoru Li

Working on it! :D

Collapse
 
armaandh profile image
Armaan Dhanji

Thanks so much, I absolutely love your videos on Prisma!

Collapse
 
kouatchres profile image
KOUATCHOUA MARK

Wonderful tutorial, Xiaoru, how you have opened my eyes to a great deal of things and forced me to transition from prisma 1 to prisma 2 and God alone knows how my work has been simplified. Esp with the graphql-codegen. My heartfelt congratulations for the work.

Collapse
 
mdirshaddev profile image
Md Irshad

This tutorial is awesome but I have a question how we can pass request, response within the context and do I have to pass in both Apollo server and nexus makeSchema. Please help me out. Recently I found this hard to understand the logic behind of context.

Collapse
 
deadcoder0904 profile image
Akshay Kadam (A2K)

Great tutorial, Xiaoru. Thanks πŸ’ͺ