Building a full-stack Task Management App with Typescript,React,Nodejs part 1
Tags: typscript, node, react, mongodb
Published: 2023-03-18 12:45:54

Task management applications are great tools to organize tasks, manage projects, and stay on top of deadlines. 

In this tutorial, we will be developing a Full-stack Task Manager Application using Typescript, Node.js, MongoDB, and React.

Here is how the final application will look like:

![Task Manager](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tbntxrja7xe4jfusyq62.PNG)

The full source code of the completed of this application can be found here [Here](https://github.com/jamesoyanna/task-manager)

We will start by building the backend of the application using Node.js, Typescript and MongoDB.

Node.js is a popular backend JavaScript runtime that allows us to build scalable and performant applications. MongoDB is a NoSQL database that is ideal for building scalable, high-performance applications with a flexible data model.

In the part 2 of this post, we will then build the frontend using React, a popular JavaScript library for building user interfaces and Typescript, an open-source programming language that adds optional static typing to JavaScript. 
React allows us to build complex and interactive user interfaces with ease.Read the part 2 [Here](https://dev.to/jamesoyanna/building-a-full-stack-task-management-app-with-typescriptreactnodejs-part-2-2ji0)

The application will have features like adding, updating, and deleting tasks. We will use RESTful API endpoints to communicate between the backend and frontend.

### Setting up the Environment:
To get started with building the Full-stack Task Manager App, you'll need to have Node.js and npm installed on your machine. 

You can download Node.js from the official website at https://nodejs.org, and npm will be installed automatically with Node.js.

You will also need to install MongoDB.  Download and install the latest version of MongoDB from the official website [here](https://www.mongodb.com/try/download/community). Alternatively, you can also use a cloud-based MongoDB service like MongoDB Atlas.

Install Typescript. If you don't have Typescript already install, you can run the following command to install it globally on your system.

`npm install -g typescript`

Initialize the project by opening the terminal and create a new directory for the project. Name it `task-manager`. 
Navigate to the directory and run the following command to initialize the project:
`npm init -y`

This will create a package.json file that will store the project configuration.

Your package.json should look like this. We will update this later on.

![packagejson file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8db1jpvjx3lkbfgxb81s.PNG)

Now let's install some of the dependencies we will need for this project.

### Set up TypeScript configuration:
Create a new file in your project directory called `tsconfig.json` and add the following contents:
{% gist https://gist.github.com/jamesoyanna/57ac3c7c613bb95fc381f9fc81240789 file=tsconfig.json %}

This file specifies the configuration options for the TypeScript compiler. Here, we are telling the compiler to target ES6, use CommonJS modules, output the compiled JavaScript files to a dist folder, and use the src folder as the root directory for our TypeScript files. We also set `esModuleInterop` to true to enable interoperability between CommonJS and ES modules.

### Installing required packages:
Now let's install the required packages for your project using the following command:

`npm install express @types/express typescript nodemon mongoose cors @types/mongoose @types/dotenv @types/cors `

Here, we are installing the express package for building our Node.js server and handling HTTP requests. 
We are also installing the TypeScript types for these packages using the @types prefix. We are also installing mongoose, a Object-Document Mapping (ODM) library for Node.js and MongoDB, Nodemon, helps to automatically restart our server.


Now, create a new folder called `src` in your project directory to store your TypeScript files.

Inside the `src` folder, create a file called app.ts and add the following contents:
{% gist https://gist.github.com/jamesoyanna/9f407944211ba5bf2f5606963ff1848d file=app.ts %}

Here we have just built a simple Node.js server with Express and TypeScript. 
We import the express package and the` Express` type from the express package. The Express type is used to define the type of the app variable, which is an instance of the express application.

Next, we create a new instance of the express application by calling the express function and assigning the returned value to the app variable.

We then use the `app.use` method to add the `express.json` middleware to our application. This middleware parses incoming requests with JSON payloads and makes the parsed data available on the req.body property.

We then define the `PORT` variable to hold the port number on which our server will listen.

Finally, we call the `app.listen` method to start the server and listen on the specified PORT. The console.log statement is used to log a message to the console indicating that the server is listening on the specified port.


To run our server, let install concurrently, a tool for running both the server and client processes at the same time (this is optional. You can decide to run you server alone). Run this command
`npm install concurrently`

Add this code
  `"start": "concurrently \"tsc -w\" \"nodemon dist/js/app\"" `to your script area in your package.json file.

Your package.json file should finally look like this:

{% gist https://gist.github.com/jamesoyanna/cff70b65a4530466b8d744beb3feebc3 file=package.json %}


You can now run `npm start` to start your server.

### Connecting to a Database:
Now, let's connect our server to a MongoDB database using Mongoose.
Make sure you install and setup mongoDB locally on your computer and create a database called `task-manager`. Learn how to set it up [here](https://medium.com/@LondonAppBrewery/how-to-download-install-mongodb-on-windows-4ee4b3493514)

We will be making some changes to our `app.ts` files by adding some code. Here is the updated app.ts file

{% gist https://gist.github.com/jamesoyanna/a3d49b9976e34c5f24734053c2095608 file=app.ts %}

`import mongoose from 'mongoose';`

Here, we added this code to import the mongoose package. 
`const uri: string  = `mongodb://localhost:27017/task-manager`

We then define a constant `uri` that holds the connection URL for our MongoDB database. The URL here specify that the MongoDB server is running on the same machine as the Node.js server and that the name of the database is `task-manager`.

We are using our locally installed MongoDB instance by specifying the hostname and port number.


The `mongoose.connect()` method is called, passing in the URI as an argument. This method returns a promise that resolves when the connection is successful, or rejects with an error if there is a problem connecting to the database.

If the connection is successful, a message is logged to the console: 'MongoDB connected successfully...'.

If there is an error connecting to the database, a message is logged to the console with the error details: _Initial Distribution API Database connection error occured - ${err}._

The `cors()` middleware is added to the Express application using `app.use(cors())`. This allows Cross-Origin Resource Sharing (CORS) for all routes.

The `dotenv` module is also imported, which loads environment variables from a `.env` file which we will create later on.

### Add Type Interface to the application:
To add a type interface to the task manager app, we can define a TypeScript interface for the task that includes the required properties.

Create a folder called `types` in your project directory and add a new file inside the `types` folder. Name it `task.ts `and add the following content:
`
// Import Mongoose and its types
import { Document } from 'mongoose';

export interface ITask extends Document {
    name: string;
    description: string;
    status: string;
  }
`

Here, we first import the Document interface from the mongoose package. We then define an interface called `Task` that extends the Document interface. 
This means that our Task interface will include all the properties and methods of the Document interface, as well as the name, description, and status properties that we've defined.

The `name` property is defined as a string, the `description` property is defined as a string, and the `status` property is defined as a boolean.

### Adding Models 
Create a folder called `models` in your project directory, add in it a new file called `tasks.ts` and the following content

```
import {ITask} from '../types/tasks';
import {model, Schema} from 'mongoose';

const taskSchema = new Schema ({
 name:{
    type: String,
    required: true
 },
 description: {
    type: String,
    required: true
 },
 status: {
    type: Boolean,
    required: true
 }
},
{timestamps: true}
)
export default model<ITask>('Task', taskSchema);
```

Here we define a Mongoose schema for the Task model, which includes the name, description, and status fields as described in the ITask interface.
`
import {ITask} from '../types/tasks';`
Firstly, we imported the `ITask` interface from the ../types/tasks module, which defines the type structure for our Task model.

`import {model, Schema} from 'mongoose'; `
We import the model and Schema classes from the mongoose package, which we use to define our schema and create a Mongoose model.

 const taskSchema = new Schema ({ ... }, {timestamps: true});
This creates a new Mongoose schema called taskSchema using the Schema class. 
We define the schema fields for name, description, and status, as well as the {timestamps: true} option, which adds createdAt and updatedAt fields to our documents to track when they were created and last updated.

` export default model<ITask>('Task', taskSchema);`
We then export a new Mongoose model called Task, which we create using the model function.

### Adding Controllers:
Controllers are modules that handles HTTP requests and responses for a specific set of related routes.

Create a new folder called `controllers` in our project directory. Add another folder the in controllers folder called `tasks` and then add an index.ts file in the `tasks` folder to define our controller functions.

Add the following content in the `index.ts` file

`{% gist https://gist.github.com/jamesoyanna/6816e4a065792ed553e3044f1af20403 file=index.ts %}`

Here we define and exports four functions: `getTasks, addTask, updateTask, and deleteTask`. 
These functions serve as controllers for our task manager app. They take in two parameters: req and res, which are objects representing the HTTP request and response, respectively. 

These parameters have types defined by the Request and Response interfaces from the express package.

The `getTasks` function queries the database for all tasks and returns them as a JSON object in the response.
 
The `addTask` function extracts the necessary fields from the request body, creates a new Task document with the mongoose model, saves it to the database, and returns the new task along with all tasks in the response. 

The `updateTask` function updates a task document in the database based on the ID provided in the URL parameters, and returns the updated task along with all tasks in the response. 

The `deleteTask` function deletes a task document from the database based on the ID provided in the URL parameters, and returns the deleted task along with all remaining tasks in the response.

### Adding Routes:
Routes are used to define the mapping between HTTP requests and the corresponding controller functions that will handle those requests.

They determine how an HTTP request is handled and responded to, and are defined using a combination of HTTP methods (e.g. GET, POST, PUT, DELETE) and URL patterns.

Create a new folder called `routes` in our project directory. add a file inside the routes folder. Name it index.ts and add the following code

```
import { Router } from 'express';
import {getTasks, addTask, updateTask, deleteTask} from '../controllers/tasks';

const router : Router =  Router();

router.get('/tasks',getTasks );
router.post('/tasks/add-task', addTask);
router.put('/edit-task/:id', updateTask);
router.delete('/delete-task/:id', deleteTask);

export default router;
```

Here,we import the `Router` object from the express package. We then import the four controllers we previously created in the task controller directory.

Next, we create a new router instance with Router(). We then use the router object to define the HTTP methods and endpoints for our routes. like this

####  GET /tasks
 - This route calls the getTasks function when the client makes a GET request to the '/tasks' endpoint.

####  POST /tasks/add-task
 - This route calls the addTask function when the client makes a POST request to the '/tasks/add-task' endpoint.

#### PUT /edit-task/:id
 - This route calls the updateTask function when the client makes a PUT request to the '/edit-task/:id' endpoint, where :id represents the ID of the task to update.

#### DELETE /delete-task/:id
This route calls the deleteTask function when the client makes a DELETE request to the '/delete-task/:id' endpoint, where :id represents the ID of the task to delete.

### Using Postman to test our endpoints:
Postman is a popular tool used for testing and interacting with APIs (Application Programming Interfaces). 

It allows you to make HTTP requests to a web server and receive responses back. Postman supports various request methods like GET, POST, PUT, DELETE, etc., and lets you view the response returned by the server.

Here's how you can use Postman:

Download and install Postman from the official website [Here](https://www.postman.com/downloads/)

 Once installed, open Postman and create a new request by clicking on the "New" button in the top left corner of the window.

Select the HTTP method you want to use from the dropdown menu (e.g. GET, POST, PUT, DELETE, etc.).

Enter the URL of the API endpoint you want to interact with in the address bar. In this case we use http://localhost:5000 for our project.

 Click on the "Send" button to send the request to the server.
 View the response returned by the server in the "Body" section of the response tab.