DEV Community

Cover image for Full Stack GraphQL - Part 1 Building a Prisma Data Model
gregleeper
gregleeper

Posted on

Full Stack GraphQL - Part 1 Building a Prisma Data Model

This blog post is part of a multi-part entry with the goal of creating a Full Stack Application using GraphQL. We will be building a catalog of recipes and have authentication in the form of JSON Web Tokens. This first part will cover the modeling of the data that Prisma uses to build the API.

The finished project will look similar to this one! Let's get started 😎

Getting Started

To speed our development, we will begin by starting from a boilerplate by Andrew Mead. This boilerplate is about 18 months old at this point, so some things have changed since he released it.

mkdir recipe-blog-post
cd recipe-blog-post/
git clone https://github.com/andrewjmead/graphql-boilerplate recipes-api
code .
Enter fullscreen mode Exit fullscreen mode

In the above code we use the terminal to create a folder for the project, change our working directory to that folder, clone the repo & rename it, and then open the project in VSCode.

Creating an Account with Prisma

In order to use the awesome services that Prisma offers, let's create an account with them and then install the global Prisma CLI.

Install the Prisma CLI

npm i -g prisma
Enter fullscreen mode Exit fullscreen mode

Then we can initiate a new Prisma service in the Prisma Cloud by using the following command.

Initiate a Prisma Cloud Service from the Command Line

prisma init prisma
Enter fullscreen mode Exit fullscreen mode

Then select the Demo Server hosted in Prisma Cloud and follow the prompts in the cli interface. For the programming language in the generated Prisma client, I'm choosing Javascript.

This gives us a folder in the root directory called prisma. Within this folder we have generated files and folders. We will concentrate on datamodel.prisma for this post. There isn't an extension for syntax highlighting in VSCode for files with the .prisma extension, so let's change this file extension to .graphql. The file will now have the name datamodel.graphql. We can install the GraphQL extension from Prisma in VSCode to get syntax highlighting.

The contents of datamodel.graphql should look like this:


type User {
  id: ID! @id
  name: String!
}
Enter fullscreen mode Exit fullscreen mode

We will replace the contents of datamodel.graphql with this:

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
  updatedAt: DateTime! @updatedAt
  createdAt: DateTime! @createdAt
  recipes: [Recipe!] @relation(name: "UserRecipes", onDelete: SET_NULL)
}

type File {
  id: ID! @id
  createdAt: DateTime! @createdAt
  updatedAt: DateTime! @updatedAt
  filename: String!
  mimetype: String!
  encoding: String!
  url: String! @unique
}

type Recipe {
  id: ID! @id
  title: String!
  handle: String! @unique
  description: String
  author: User! @relation(name: "UserRecipes", onDelete: SET_NULL)
  image: File @relation(name: "RecipeImage", onDelete: CASCADE)
  ingredients: [String!]! @scalarList(strategy: RELATION)
  directions: String
  categories: [Category!]!
    @relation(name: "RecipeCategories", onDelete: SET_NULL)
  tags: [Tag!]! @relation(name: "RecipeTags", onDelete: SET_NULL)
}

type Tag {
  id: ID! @id
  name: String!
  recipes: [Recipe] @relation(name: "RecipeTags", onDelete: SET_NULL)
}

type Category {
  id: ID! @id
  name: String!
  recipes: [Recipe] @relation(name: "RecipeCategories", onDelete: SET_NULL)
}
Enter fullscreen mode Exit fullscreen mode

Breaking Down the Data Model

The type keyword gives us a table in the database representing that entity. There are also several directives such as, @unique and @id that give Prisma a little more information about that field or type. More info on directives can be found in Prisma's documentation.

The relational data is annotated with the @relation directive. We have used this directive several times in the above code. This creates a relational table showing the connection between two entities. The relational tables are named according to the name argument in the @relation directive.

Close Look at the User Type

Let's dig into the User type to better understand the directives and relations.

type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
  updatedAt: DateTime! @updatedAt
  createdAt: DateTime! @createdAt
  recipes: [Recipe!] @relation(name: "UserRecipes", onDelete: SET_NULL)
}
Enter fullscreen mode Exit fullscreen mode

The ! on each field type means that the field cannot be null when the User is created.

The id field will automatically be created by Prisma when a new User is created and using the ID! type along with the @id directive tells Prisma this will be the case.

The name field accepts a String!, and similarly the email and password fields accept a String!. The email field does a @unique directive meaning that an email address cannot be used on more than one User.

The updatedAt and createdAt fields both accept a DateTime! type and these are automatically generated by Prisma using the appropriate directives.

Lastly, we have the recipes field, which is a realtion to the Recipe type. The plural name of the field recipes is intentional as a User can have more than one Recipe. This is signified in the type portion of the recipes field as we have a set of [Recipe!]. The ! inside the square brackets does have significant meaning here. It sets the API up so that the creation of a User does not have to link to any recipes (the field can be null), that is why there is no ! outside the square brackets. Having the ! inside the brackets means that when a mutation occurs where a set of recipes is linked to a user, the type must be Recipe.

The @relation(name: "UserRecipes", onDelete: SET_NULL) directive sets up a table named UserRecipes that connects a User to a Recipe on each row. The Recipe entity uses the same directive to connect the Recipe to the author. The rest of the datamodel file follows the same patterns as the User type.

Changing the Prisma.yml File

Now that the datamodel is ready to go, we need to make a few changes the prisma.yml file. The contents will look like this:

endpoint: https://eu1.prisma.sh/recipe-catalog/whatever-your-path-is/dev
datamodel: datamodel.graphql

generate:
  - generator: graphql-schema
    output: ./generated/prisma-client/prisma.graphql
hooks:
  post-deploy:
    - prisma generate

Enter fullscreen mode Exit fullscreen mode

Deployment

Once the above changes are saved, we can run the command:

prisma delpoy
Enter fullscreen mode Exit fullscreen mode

This will have Prisma generate the GraphQL schema, including all the resolvers. It also gives us an active GraphQL Playground to explore using the auto-generated resolvers, along with docs.

GraphQL Playground

Summary

While we didn't use the boilerplate mentioned above in this post, it did give us a folder structure to work off of in subsequent entries. If you have any questions or comments, please let me know! My twitter handle is @gregleeper.

Top comments (0)