DEV Community

Cover image for Beginner friendly guide to nodejs express-server with mongodb,graphql and typescript
Dennis kinuthia
Dennis kinuthia

Posted on • Updated on

Beginner friendly guide to nodejs express-server with mongodb,graphql and typescript

In this guide i’ll walk you through how to set up node s server frote point of view of a beginner who’s being tinkering around for the last 6 months and help you avoid the common issues i ran into in the process

I;ll assume you know the basic in javascript,typescript and graphql

But i’ll try and organise the github commits from the most basic

the typescript setup might be little cumbersome so i’d advise to clone the repo first before beginning this tutorial

Navigate to the initial commit and download or clone repo if you have git installed

Repo

You’ll also need to install and setup mongodb on your device or use mongo atlas , am not a fan of mongodb compass because of its lack of dark mode so i use the vscode extension MySQL database viewer:

https://marketplace.visualstudio.com/items?itemName=cweijan.vsc

Install and connect to sql and nosql databases

Image description

You might also vscode extensions for

Graphql and typescript

Run “npm install” in it’s root directory

Then npm run watch or yarn watch to watch for ts changes

Open another terminal to run npm start or yarn start

import  express  from "express";
import cors from 'cors'
import { ApolloServer } from 'apollo-server-express';
import { gql } from 'apollo-server-express';

const PORT=4000;

const typeDefs = 
gql`
    type Query {
      defaultPost:String
     }
`;
const resolvers = {
  Query: {
    defaultPost: () => "eat your vegetables",
  },
};

const startServer=async()=>
{
const app = express();


const allowedOrigins = [
'http://localhost:3000',
'http://localhost:3001',
'https://studio.apollographql.com'
];
const corsOptions = {
credentials: true,
  origin: function(origin, callback){
   if(!origin) return callback(null, true);
    if(allowedOrigins.indexOf(origin) === -1){
      var msg = 'The CORS policy for this site does not ' +
                'allow access from the specified Origin.';
      return callback(new Error(msg), false);
    }
    return callback(null, true);
  }
}
app.use(cors(corsOptions))
//rest routes
app.get("/", (req, res) => {
res.json({
    data: "API is working...",
  });
});

const server = new ApolloServer({
  typeDefs,
  resolvers,
});
await server.start();

server.applyMiddleware({ app });

app.listen(PORT, () => {
  console.log(` Server is running at http://localhost:${PORT}`);
});
}
startServer().catch(e=>console.log("error strting server======== ",e))


Enter fullscreen mode Exit fullscreen mode

our server is now ready navigate to
http://localhost:4000/graphql

to preview our server in apollo's playground and run our first query

Image description

on the right hand side we have all the operatons which you can navigate to by clicking the the pluss button and adding field then run it and the response is displayed in the left hand side.

now we'll add mongodb into the project:

var uri = "mongodb://localhost:27017/testmongo";

//@ts-ignore
mongoose.connect(uri, { useUnifiedTopology: true, useNewUrlParser: true })
.then(()=>console.log("connected to newmango db"))


Enter fullscreen mode Exit fullscreen mode

this will auto-create a newmango collection for us
now we'll create a new directory models/TestModel.ts

then add this code to create a new mongo db model

import mongoose from "mongoose";
const Schema = mongoose.Schema;

const TestSchema = new Schema({
  title: {
    type: String,
    required: true
  },
  desc: {
    type: String,
    required: true
  },

},
//add this for auto createdAt and updatedat fields
{timestamps:true}
);

export const TestModel= mongoose.model("Test", TestSchema);
Enter fullscreen mode Exit fullscreen mode

then we'll also create resolver/TestResolver.ts and typeDefs/typeDef.ts

import { TestModel } from "./../model/TestModel";
export const resolvers = {
  Query: {
    defaultPost: () => "eat your vegetables",
    getItems: async () => {
      const chats = await TestModel.find({});
      console.log("holt output ======", chats);
      return chats;
    },
  },
  Mutation: {
    //shape of params (parent,args, context, info)
    addItem: async (parent, { title, desc }, context, info) => {
   let item={}
   let error={}     
   try{
      const newItem = await new TestModel({
        title,
        desc,
      });
   item=await newItem.save()
    console.log("item  ==== ",item)

    }catch(e){
    console.log("addTest error response =====", e.message);
    error=e
           }

         return {
            item:item,
            error:{
           //@ts-ignore
            message:error.message
            }
          };



 },
  },
};

Enter fullscreen mode Exit fullscreen mode
import { gql } from 'apollo-server-express';

export const typeDefs = 
gql`type Item{
    title:String,
    desc:String
   }
   type Error{
   message:String
   }
   type ItemResponse{
    item:Item
    error:Error
   }
    type Query {
      defaultPost:String,
      getItems:[Item]
     },

     type Mutation{
      addItem(title:String,desc:String):ItemResponse
     }


`;

Enter fullscreen mode Exit fullscreen mode

add the respective code and import it in the index.ts

import  express  from "express";
import cors from 'cors'
import { ApolloServer } from 'apollo-server-express';
import mongoose  from 'mongoose';
import { resolvers } from './resolvers/TestResolver';
import { typeDefs } from './typeDefs/typedefs';

const PORT=4000;

const startServer=async()=>
{
const app = express();


const allowedOrigins = [
'http://localhost:3000',
'http://localhost:3001',
'https://studio.apollographql.com'
];
const corsOptions = {
credentials: true,
  origin: function(origin, callback){
   if(!origin) return callback(null, true);
    if(allowedOrigins.indexOf(origin) === -1){
      var msg = 'The CORS policy for this site does not ' +
                'allow access from the specified Origin.';
      return callback(new Error(msg), false);
    }
    return callback(null, true);
  }
}
app.use(cors(corsOptions))
var uri = "mongodb://localhost:27017/testmongo";

//@ts-ignore
mongoose.connect(uri, { useUnifiedTopology: true, useNewUrlParser: true })
.then(()=>console.log("connected to newmango db"))

//rest routes
app.get("/", (req, res) => {
res.json({
    data: "API is working...",
  });
});


const server = new ApolloServer({
  typeDefs,
  resolvers,
});
await server.start();

server.applyMiddleware({ app });

app.listen(PORT, () => {
  console.log(` Server is running at http://localhost:${PORT}`);
});
}
startServer().catch(e=>console.log("error strting server======== ",e))

Enter fullscreen mode Exit fullscreen mode

add the respective code and import it in the index.ts

The typedefs define what the data should look like and all it’s types

For example we have a custom type Item which is an object with the fields title of type Strung and desc of type String too

We also have to define the queries,mutations and subscriptions

These definitions are used to shape the data we’ll pass to and receive from our resolvers

Our resolver is comprised of a simple getItems query which returns an array of items from our mongo db

Image description

Image description

The addItem mutation takes title and desc and saves it to mongo then is returns an item response

Image description

Image description

has more information for more complex mutations and queries

but if you've noticeed my code is still full of //@ts-ignore decorators
because we are not using typescript it to it's fullest
next time we'll set up type-graphql and typegoose for better type-checking which makes development much easier

we'll also handle delete and update in mongodb
feel free to explore more till then

Top comments (0)