We'll be working in a terminal - be it the standalone teminal - or the integrated terminal in your text editor.
Initialize a repository in an empty folder, say, we call ours express-gql-api
.:
mkdir express-gql-api
# enter the project foldercd express-gql-api
Initialize the folder as a node and git project:
npm init -y
git init
Initialize a Readme Having a Readme is essential for any project - this is the document people will see when they come across your repository in Github.
Initalize the source directory
This is where we will place our .ts
files
mkdir src
TypeScript is usually compiled to JavaScript and which is the code that is actually run. Assuming you already have the TypeScript installed, we will write the configuration file that tells the TypeScript compiler how to compile out files into JavaScript:
Initialize a tsconfig.json
file in your root directory from the terminal
tsc --init
. Working in the text editor, we will set the following compiler options:
"rootDir"
- this is the directory where the TypeScript compiler will search for .ts
files to compile into JavaScript. In our case, the root directory is the src
folder:
{ "compilerOptions": { //... "rootDir": "./src" //... }}
"outDir"
- this is the directory where the compiled JavaScript will be placed:
In our case, we will call our output directory "dist"
{ "compilerOptions": { //... "rootDir": "./src", "ourDir": "./dist" //... }}
Finally, we will edit the package.json file so that we have a smooth time running the project. Add the following line under script in package.json
:
"scripts":{ //... "start" : "nodemon dist/index.js", //...}
This is the basic setup that we need before we get started
We will be working with a few packages that we need to install:
express
- since we are buiding an express serverexpress-graphql
- this is the express middleware that will allow us to build our graphQL endpointgraphql-tools
- A package that helps build the GraphQL Schemamongoose
- The library that will allow us to connect to a MongoDB databaseBefore we jump right into installing the packages, let's create a .gitignore
file at the root folder and add node_modules
so that git doesn't track npm packages:
echo node_modules > .gitignore
To install all the tools, we can do so in one command:
yarn add -s express express-graphql graphql-tools mongoose nodemon
Before we start writing some code, we need to have our TypeScript compiler running so that we can generate the JavaScript files as we go. So, in a separate window, run the typescript compiler with a watch flag:
tsc -w
And now we are ready to build our api
Let's add some files to our file structure first:
📦express-gql-api┣ 📂src┣ 📜.gitignore┣ 📜Readme.md┣ 📜package.json┗ 📜tsconfig.json
However, let's add some files in the src
folder first
Create an empty directory in the src
folder called data
- this is where we willl be placing out database connectors, types, schemas and resolver files.
Create the following files to match the following structure:
📦express-gql-api┣ 📂src┃ ┣ 📂data┃ ┃ ┣ 📜db.ts┃ ┃ ┣ 📜resolvers.ts┃ ┃ ┣ 📜schema.ts┃ ┃ ┗ 📜types.ts┃ ┗ 📜index.ts┣ 📜Readme.md┣ 📜package.json┗ 📜tsconfig.json
GraphQL requires a schema to be defined. A schema what graphQL uses to know what type of data to expect.
a user
type
a UserInput
input - that has the same structure as the User
type
a Query
type - where we will define all the queries
a Mutation
type - where we will define the mutations
import { resolvers } from './resolvers'import { makeExecutableSchema } from 'graphql-tools'
const typeDefs = ` type User { name: String username: String } input UserInput { name: String username: String } type Query { getUser(username: String): User } type Mutation{ createUser(user: UserInput): User } `// Build the schema and exportconst schema = makeExecutableSchema({ typeDefs, resolvers })export { schema }
type.ts
export class UserType { constructor(public name: String, public username: String) {}}
Before we move into this step, we will need to first set up our database. One can do so by following this process:
connect
to your cluster. Further instructions can be found hereconnect your application
optionNode.js
Version 3.6 or later
.<password>
with your password and also pick a name for our database
{' '}mongodb+srv://amani:AEDPfTeq61WH04NL@cluster0.9ntf0.mongodb.net/bliss?retryWrites=true&w=majority
db.ts
In the db.js
file, we will import mongoose
and then define a new schema for the database - in our case, the only schema we will need is the user schema.
import mongoose from 'mongoose'const Schema = mongoose.Schema
// @ts-ignoreconst connectionString: String = process.env.MONGO_DB// @ts-ignoremongoose.connect(connectionString, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, useCreateIndex: true})
const UserSchema = new Schema({ name: String, username: String})
const User = mongoose.model('User', UserSchema)
export { User }
resolvers.ts
The resolvers are the functions that are run whenever the endpoint is run - so you need to define a function for each query and mutation as we will do below:
import { UserType } from './types'
// import the User from the databaseimport { User } from './db'
export const resolvers = { Query: { //@ts-ignore getUser: (root, { username }) => { return User.findOne({ username: username }) .then((user: UserType) => { return user }) .catch((error: any) => { console.log(error.message) }) } }, Mutation: { // @ts-ignore createUser: async (root, { user }) => { const newUser = new User({ name: user.name, username: user.username }) await newUser.save() return newUser } }}
index.ts
Our index.ts
file is where all the majic happens. We will begin by importing the necessary packages and instantiating a new express app. Then we will initialize the connection to the database and attach the grapqlHTTP
middleware function with our schema and graphiql
- which we can use to explore the api:
import express from 'express'import { graphqlHTTP } from 'express-graphql'import { schema } from './data/schema'
// Initialize appconst app = express()require('./data/db')
// the graphQL endpoint at /graphql.app.use('/graphql', graphqlHTTP({ schema: schema, graphiql: true }))
app.get('*', (req, res) => { res.json({ message: 'Welcome to the api' })})
const PORT = 7000app.listen(PORT, () => { console.log(`api is running on port ${PORT}`)})
Before we run the server, we will need to add our mongoDB connection string to the environment variables:
export MONGO_DB='mongodb+srv://amani:AEDPfTeq61WH04NL@cluster0.9ntf0.mongodb.net/bliss?retryWrites=true&w=majority'
Now, we are ready to run the server 🚀
npm run start
And we can run the server and explore our api. Here's an example of a mutation that you can make with the api:
We can add a user by making a mutation on the api:
mutation createUser ($input:UserInput){ createUser(user:$input) { name username } }
We can then pass in the user input using the query variables:
{ "input": { "name": "Laurence", "username": "laudebugs" } }
Here's how the mutation looks like:
If we were to then ask the api for a certain user, we can make the query by:
query { getUser (username:"laudebugs"){ name } }
You can check out the repo here
express
:npm install --save-dev express
Last modified on: Fri Jun 24 2022