Beginner friendly guide to nodejs express-server with mongodb,graphql and typescript
Tags: typescript, node, mongodb, express
Published: 2022-05-20 13:57:44

 










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](https://github.com/tigawanna/node-server-template.git)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fiozi0flmro1nzqhczon.png)



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))


```

 
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fmdkhi1s7xs64gfet47z.png)



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"))


```

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);
```




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
            }
          };
    
 

 },
  },
};

```



    
```
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
     }


`;

```

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))

```


 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zws54qqwn7zddwo3dhjg.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1skaujver0p7rsk03vqc.png)




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



![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wujhk3o0gl6h9797j9ia.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lat0esvas3csgyesoe9.png)




 



[the docs page]:(https://www.apollographql.com/docs/)  
 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