DEV Community

Abayomi Ogunnusi
Abayomi Ogunnusi

Posted on

Class Typescript

Create a new app

npm init -y
npm install typescript ts-node mongoose reflect-metadata express dotenv cors
Enter fullscreen mode Exit fullscreen mode

Dev dependencies

npm install --save-dev @types/node @types/express @types/dotenv @types/cors ts-node-dev
Enter fullscreen mode Exit fullscreen mode

Create a tsconfig.json file with the following content:

{
  "compilerOptions": {
    "target": "ES2019",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": ["src/**/*.ts"],
  "exclude": ["node_modules"]
}
Enter fullscreen mode Exit fullscreen mode

Update your package.json scripts:

"scripts": {
    "dev": "ts-node-dev --respawn --transpileOnly src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
Enter fullscreen mode Exit fullscreen mode

Create the following folder structure:

mkdir -p src/{controllers,repositories,services,models,dtos,config,interfaces,utils}
Enter fullscreen mode Exit fullscreen mode

Create a file src/config/database.ts for setting up Mongoose:

import mongoose from "mongoose";
import dotenv from "dotenv";

dotenv.config();

const connectDB = async () => {
  try {
    await mongoose.connect(process.env.DATABASE_URL || "", {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log("MongoDB connected");
  } catch (error) {
    console.error("MongoDB connection error:", error);
    process.exit(1);
  }
};

export default connectDB;
Enter fullscreen mode Exit fullscreen mode

Create a file src/models/User.ts:

import { Schema, model, Document } from "mongoose";

interface IUser extends Document {
  name: string;
  email: string;
}

const userSchema = new Schema<IUser>({
  name: { type: String, required: true },
  email: { type: String, required: true },
});

const User = model<IUser>("User", userSchema);

export { User, IUser };
Enter fullscreen mode Exit fullscreen mode

Create a file src/interfaces/BaseRepository.ts:

export interface BaseRepository<T> {
  create(data: T): Promise<T>;
  findAll(): Promise<T[]>;
  findById(id: string): Promise<T | null>;
  update(id: string, data: T): Promise<T | null>;
  delete(id: string): Promise<T | null>;
}
Enter fullscreen mode Exit fullscreen mode

Create a file src/repositories/BaseRepository.ts:

import { Model, Document } from "mongoose";
import { BaseRepository } from "../interfaces/BaseRepository";

export class MongooseBaseRepository<T extends Document>
  implements BaseRepository<T>
{
  private model: Model<T>;

  constructor(model: Model<T>) {
    this.model = model;
  }

  async create(data: T): Promise<T> {
    return await this.model.create(data);
  }

  async findAll(): Promise<T[]> {
    return await this.model.find();
  }

  async findById(id: string): Promise<T | null> {
    return await this.model.findById(id);
  }

  async update(id: string, data: T): Promise<T | null> {
    return await this.model.findByIdAndUpdate(id, data, { new: true });
  }

  async delete(id: string): Promise<T | null> {
    return await this.model.findByIdAndDelete(id);
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a file src/repositories/UserRepository.ts:

import { User, IUser } from "../models/User";
import { MongooseBaseRepository } from "./BaseRepository";

export class UserRepository extends MongooseBaseRepository<IUser> {
  constructor() {
    super(User);
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a file src/services/UserService.ts:

import { IUser } from "../models/User";
import { UserRepository } from "../repositories/UserRepository";

export class UserService {
  private userRepository: UserRepository;

  constructor() {
    this.userRepository = new UserRepository();
  }

  async create(data: IUser) {
    return await this.userRepository.create(data);
  }

  async findAll() {
    return await this.userRepository.findAll();
  }

  async findById(id: string) {
    return await this.userRepository.findById(id);
  }

  async update(id: string, data: IUser) {
    return await this.userRepository.update(id, data);
  }

  async delete(id: string) {
    return await this.userRepository.delete(id);
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a file src/controllers/UserController.ts:

import { Request, Response } from "express";
import { UserService } from "../services/UserService";
import { IUser } from "../models/User";

export class UserController {
  private userService: UserService;

  constructor() {
    this.userService = new UserService();

    // Bind the methods to the current context
    this.create = this.create.bind(this);
    this.findAll = this.findAll.bind(this);
    this.findById = this.findById.bind(this);
    this.update = this.update.bind(this);
    this.delete = this.delete.bind(this);
  }
  async create(req: Request, res: Response) {
    const data: IUser = req.body;
    const user = await this.userService.create(data);
    res.json(user);
  }

  async findAll(req: Request, res: Response) {
    const users = await this.userService.findAll();
    res.json(users);
  }

  async findById(req: Request, res: Response) {
    const id = req.params.id;
    const user = await this.userService.findById(id);
    res.json(user);
  }

  async update(req: Request, res: Response) {
    const id = req.params.id;
    const data: IUser = req.body;
    const user = await this.userService.update(id, data);
    res.json(user);
  }

  async delete(req: Request, res: Response) {
    const id = req.params.id;
    const user = await this.userService.delete(id);
    res.json(user);
  }
}
Enter fullscreen mode Exit fullscreen mode

Create a file src/routes/userRoutes.ts:

import { Router } from "express";
import { UserController } from "../controllers/UserController";

const router = Router();

const userController = new UserController();

router.post("/", userController.create);
router.get("/", userController.findAll);
router.get("/:id", userController.findById);
router.put("/:id", userController.update);
router.delete("/:id", userController.delete);

export default router;
Enter fullscreen mode Exit fullscreen mode

Create a file src/index.ts:

import express from "express";
import cors from "cors";
import dotenv from "dotenv";
import connectDB from "./config/database";
import userRoutes from "./routes/userRoutes";

dotenv.config();
connectDB();

const app = express();

app.use(express.json());
app.use(cors());

app.use("/users", userRoutes);

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Create a .env file with the following content:

PORT=5000
DATABASE_URL=mongodb://localhost:27017/test
Enter fullscreen mode Exit fullscreen mode

Start the server

npm run dev
Enter fullscreen mode Exit fullscreen mode

Create a user.http file

### Create a user
POST http://localhost:5000/users
Content-Type: application/json

{
  "name": "John Doe",
  "email": "a@c.c",
}

### Get all users
GET http://localhost:5000/users

### Get a user by id
GET http://localhost:5000/users/1

### Update a user
PUT http://localhost:5000/users/1
Content-Type: application/json

{
  "name": "Jane Doe",
  "email": "b@c.c",
}

### Delete a user
DELETE http://localhost:5000/users/1
Enter fullscreen mode Exit fullscreen mode

Run the following command to start the server

npm run dev
Enter fullscreen mode Exit fullscreen mode

Top comments (0)