⭐️Step 2 — Database setup

The finished repository for stop 1: https://github.com/tomanagle/apollo-graphql-server/tree/master/2-database-setup

In this step, we are going to set up Mongoose and a card model so data can be read and written to a database.

Add mongoose as a dependency:

yarn add mongoose yarn add @types/node -D

Create a connection to MongoDB with Mongoose, so you can read and write to your database:

mkdir src/database touch src/database/connect.ts

Add the connection to app.ts to initialize the connection:

Create your model and controller files:

mkdir src/models mkdir src/controllers touch src/models/card.model.ts touch src/controllers/card.controller.ts

🔥 Tip: I put the word model and controller in the file name to make it easier to see what I’m working on within my editor. Because I name each model, controller, and resolver after the object that it’s for, it’s helpful to have a little tag that keeps them separate.

Add the code to your model:

While this is a valid Mongoose model, we’re using TypeScript so we may as well take advantage of it.

Add the DefinentlyTyped Mongoose package:

yarn add @types/mongoose -D

We can now import Document and create an interface that extends it:

If you want to learn more about creating strongly typed Mongoose models, I have written an article about it. https://medium.com/@tomanagle/strongly-typed-models-with-mongoose-and-typescript-7bc2f7197722

Add a function to your card controller that will create a card with the given input:

Finally, we will add a function that returns all the cards in the database. The function will take an optional parameter that allows the query to limit the number of results.

⭐ Step 3 — Bring it all together with a resolver

The finished repository for step 3: https://github.com/tomanagle/apollo-graphql-server/tree/master/3-mutations

In this step, we will get into the real differentiation between a REST API and a GraphQL API. Instead of creating an endpoint for our API, we are going to create a resolver.

Before we start adding new code, we’ll do a bit of cleanup on the project directory so far.

Remove the hardcoded cards array from the app.ts:

Move your resolver from your app.ts into a new resolver.ts file

touch src/resolvers.ts

Import your new resolver file into app.ts:

You’ll notice that you have an error in your resolver file, it doesn’t know how to resolve the ‘Cards’ query. We’re going to tell the resolver that it should use the getAllCards function in our controller to resolve the query. Import the function and its interface from the controller:

Connect your ‘getAllcards’ function with the resolver:

Add a Mutations object to your resolvers and inside that, add a function called ‘CreateCard’. The function will call and return the ‘createCard’ function in the card controller.

You should see an error in your console, ‘“Mutations” defined in resolvers, but not in schema’, this is good. It means that your schema is aware of your revolvers and it’s telling you that your schema is behind your resolvers. If something doesn’t exist in your schema, you won’t be able to access it via the GraphQL API.

The fix, I hope, seems obvious: add the mutation to the schema.

🔥 Tip: When I create mutations, I follow a set of rules:

Start the mutation name with ‘Create’ or ‘Update’ Add the object type after the ‘Create’ or ‘Update’ prefix Create an input type that takes your mutation’s name, followed by ‘Input’ Give your mutation exactly one input and call it ‘input’ Return the object that’s referenced in the mutation’s name

For example, if I am going to create a ‘Card’ object, I would call the mutation ‘CreateCard’. I would then create an input type called ‘CreateCardInput’ and it would always return the created ‘Card’ object.

Even if you don’t like my convention and you have a better way of doing it, make sure you’re consistent. Consistency in your naming conventions and return types will make your API predictable and easy to use.

Add the new type and mutation to your schema.ts file:

You can now go into your GraphQL playground and make a mutation. You could see the data being returned from the mutation and a new card appear in the database.

You may not have spotted it yet, but we have a tiny little bug that will cause a giant headache to any front end developer that wants to use our API. Our cards don’t have IDs. This may seem trivial but the client will use them to keep track of the data that’s in the store. Let’s go back and fix our mistake.

Go back into schema.ts and add _id as type ID to your ‘Card’ type and make it mandatory.

The reason I use _id instead of id is because that that is what MongoDB calls it. Unless you trust yourself to rename the variable on every query to id, I’d suggest you do the same.