DEV Community

Cover image for Building a full-stack Task Management App with Typescript,React,Nodejs part 1
James Oyanna
James Oyanna

Posted on

Building a full-stack Task Management App with Typescript,React,Nodejs part 1

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

The full source code of the completed of this application can be found here Here

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

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

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:

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:

Here we have just built a simple Node.js server with Express and TypeScript.
We import the express package and theExpress 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:

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

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

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('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

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

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.

Top comments (0)